~ubuntu-branches/ubuntu/wily/sflphone/wily

« back to all changes in this revision

Viewing changes to daemon/libs/pjproject-2.2.1/pjlib/src/pj/os_core_win32.c

  • Committer: Package Import Robot
  • Author(s): Francois Marier, Francois Marier, Mark Purcell
  • Date: 2014-10-18 15:08:50 UTC
  • mfrom: (1.1.12)
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20141018150850-2exfk34ckb15pcwi
Tags: 1.4.1-0.1
[ Francois Marier ]
* Non-maintainer upload
* New upstream release (closes: #759576, #741130)
  - debian/rules +PJPROJECT_VERSION := 2.2.1
  - add upstream patch to fix broken TLS support
  - add patch to fix pjproject regression

[ Mark Purcell ]
* Build-Depends:
  - sflphone-daemon + libavformat-dev, libavcodec-dev, libswscale-dev,
  libavdevice-dev, libavutil-dev
  - sflphone-gnome + libclutter-gtk-1.0-dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: os_core_win32.c 4537 2013-06-19 06:47:43Z riza $ */
 
2
/* 
 
3
 * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
 
4
 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
 
5
 *
 
6
 * This program is free software; you can redistribute it and/or modify
 
7
 * it under the terms of the GNU General Public License as published by
 
8
 * the Free Software Foundation; either version 2 of the License, or
 
9
 * (at your option) any later version.
 
10
 *
 
11
 * This program is distributed in the hope that it will be useful,
 
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
 * GNU General Public License for more details.
 
15
 *
 
16
 * You should have received a copy of the GNU General Public License
 
17
 * along with this program; if not, write to the Free Software
 
18
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
 
19
 */
 
20
#include <pj/os.h>
 
21
#include <pj/pool.h>
 
22
#include <pj/log.h>
 
23
#include <pj/string.h>
 
24
#include <pj/guid.h>
 
25
#include <pj/rand.h>
 
26
#include <pj/assert.h>
 
27
#include <pj/errno.h>
 
28
#include <pj/except.h>
 
29
#include <stddef.h>
 
30
#include <stdlib.h>
 
31
#include <stdio.h>
 
32
 
 
33
#if defined(PJ_HAS_WINSOCK_H) && PJ_HAS_WINSOCK_H != 0
 
34
#  include <winsock.h>
 
35
#endif
 
36
 
 
37
#if defined(PJ_HAS_WINSOCK2_H) && PJ_HAS_WINSOCK2_H != 0
 
38
#  include <winsock2.h>
 
39
#endif
 
40
 
 
41
/* Activate mutex related logging if PJ_DEBUG_MUTEX is set, otherwise
 
42
 * use default level 6 logging.
 
43
 */
 
44
#if defined(PJ_DEBUG_MUTEX) && PJ_DEBUG_MUTEX
 
45
#   undef PJ_DEBUG
 
46
#   define PJ_DEBUG         1
 
47
#   define LOG_MUTEX(expr)  PJ_LOG(5,expr)
 
48
#else
 
49
#   define LOG_MUTEX(expr)  PJ_LOG(6,expr)
 
50
#endif
 
51
 
 
52
#define THIS_FILE       "os_core_win32.c"
 
53
 
 
54
/*
 
55
 * Implementation of pj_thread_t.
 
56
 */
 
57
struct pj_thread_t
 
58
{
 
59
    char            obj_name[PJ_MAX_OBJ_NAME];
 
60
    HANDLE          hthread;
 
61
    DWORD           idthread;
 
62
    pj_thread_proc *proc;
 
63
    void           *arg;
 
64
 
 
65
#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
 
66
    pj_uint32_t     stk_size;
 
67
    pj_uint32_t     stk_max_usage;
 
68
    char           *stk_start;
 
69
    const char     *caller_file;
 
70
    int             caller_line;
 
71
#endif
 
72
};
 
73
 
 
74
 
 
75
/*
 
76
 * Implementation of pj_mutex_t.
 
77
 */
 
78
struct pj_mutex_t
 
79
{
 
80
#if PJ_WIN32_WINNT >= 0x0400
 
81
    CRITICAL_SECTION    crit;
 
82
#else
 
83
    HANDLE              hMutex;
 
84
#endif
 
85
    char                obj_name[PJ_MAX_OBJ_NAME];
 
86
#if PJ_DEBUG
 
87
    int                 nesting_level;
 
88
    pj_thread_t        *owner;
 
89
#endif
 
90
};
 
91
 
 
92
/*
 
93
 * Implementation of pj_sem_t.
 
94
 */
 
95
typedef struct pj_sem_t
 
96
{
 
97
    HANDLE              hSemaphore;
 
98
    char                obj_name[PJ_MAX_OBJ_NAME];
 
99
} pj_mem_t;
 
100
 
 
101
 
 
102
/*
 
103
 * Implementation of pj_event_t.
 
104
 */
 
105
struct pj_event_t
 
106
{
 
107
    HANDLE              hEvent;
 
108
    char                obj_name[PJ_MAX_OBJ_NAME];
 
109
};
 
110
 
 
111
/*
 
112
 * Implementation of pj_atomic_t.
 
113
 */
 
114
struct pj_atomic_t
 
115
{
 
116
    long value;
 
117
};
 
118
 
 
119
/*
 
120
 * Flag and reference counter for PJLIB instance.
 
121
 */
 
122
static int initialized;
 
123
 
 
124
/*
 
125
 * Static global variables.
 
126
 */
 
127
static pj_thread_desc main_thread;
 
128
static long thread_tls_id = -1;
 
129
static pj_mutex_t critical_section_mutex;
 
130
static unsigned atexit_count;
 
131
static void (*atexit_func[32])(void);
 
132
 
 
133
/*
 
134
 * Some static prototypes.
 
135
 */
 
136
static pj_status_t init_mutex(pj_mutex_t *mutex, const char *name);
 
137
 
 
138
 
 
139
/*
 
140
 * pj_init(void).
 
141
 * Init PJLIB!
 
142
 */
 
143
PJ_DEF(pj_status_t) pj_init(void)
 
144
{
 
145
    WSADATA wsa;
 
146
    char dummy_guid[32]; /* use maximum GUID length */
 
147
    pj_str_t guid;
 
148
    pj_status_t rc;
 
149
 
 
150
    /* Check if PJLIB have been initialized */
 
151
    if (initialized) {
 
152
        ++initialized;
 
153
        return PJ_SUCCESS;
 
154
    }
 
155
 
 
156
    /* Init Winsock.. */
 
157
    if (WSAStartup(MAKEWORD(2,0), &wsa) != 0) {
 
158
        return PJ_RETURN_OS_ERROR(WSAGetLastError());
 
159
    }
 
160
 
 
161
    /* Init this thread's TLS. */
 
162
    if ((rc=pj_thread_init()) != PJ_SUCCESS) {
 
163
        return rc;
 
164
    }
 
165
    
 
166
    /* Init logging */
 
167
    pj_log_init();
 
168
 
 
169
    /* Init random seed. */
 
170
    /* Or probably not. Let application in charge of this */
 
171
    /* pj_srand( GetCurrentProcessId() ); */
 
172
 
 
173
    /* Initialize critical section. */
 
174
    if ((rc=init_mutex(&critical_section_mutex, "pj%p")) != PJ_SUCCESS)
 
175
        return rc;
 
176
 
 
177
    /* Startup GUID. */
 
178
    guid.ptr = dummy_guid;
 
179
    pj_generate_unique_string( &guid );
 
180
 
 
181
    /* Initialize exception ID for the pool. 
 
182
     * Must do so after critical section is configured.
 
183
     */
 
184
    rc = pj_exception_id_alloc("PJLIB/No memory", &PJ_NO_MEMORY_EXCEPTION);
 
185
    if (rc != PJ_SUCCESS)
 
186
        return rc;
 
187
 
 
188
    /* Startup timestamp */
 
189
#if defined(PJ_HAS_HIGH_RES_TIMER) && PJ_HAS_HIGH_RES_TIMER != 0
 
190
    {
 
191
        pj_timestamp dummy_ts;
 
192
        if ((rc=pj_get_timestamp_freq(&dummy_ts)) != PJ_SUCCESS) {
 
193
            return rc;
 
194
        }
 
195
        if ((rc=pj_get_timestamp(&dummy_ts)) != PJ_SUCCESS) {
 
196
            return rc;
 
197
        }
 
198
    }
 
199
#endif   
 
200
 
 
201
    /* Flag PJLIB as initialized */
 
202
    ++initialized;
 
203
    pj_assert(initialized == 1);
 
204
 
 
205
    PJ_LOG(4,(THIS_FILE, "pjlib %s for win32 initialized",
 
206
              PJ_VERSION));
 
207
 
 
208
    return PJ_SUCCESS;
 
209
}
 
210
 
 
211
/*
 
212
 * pj_atexit()
 
213
 */
 
214
PJ_DEF(pj_status_t) pj_atexit(void (*func)(void))
 
215
{
 
216
    if (atexit_count >= PJ_ARRAY_SIZE(atexit_func))
 
217
        return PJ_ETOOMANY;
 
218
 
 
219
    atexit_func[atexit_count++] = func;
 
220
    return PJ_SUCCESS;
 
221
}
 
222
 
 
223
 
 
224
/*
 
225
 * pj_shutdown(void)
 
226
 */
 
227
PJ_DEF(void) pj_shutdown()
 
228
{
 
229
    int i;
 
230
 
 
231
    /* Only perform shutdown operation when 'initialized' reaches zero */
 
232
    pj_assert(initialized > 0);
 
233
    if (--initialized != 0)
 
234
        return;
 
235
 
 
236
    /* Display stack usage */
 
237
#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
 
238
    {
 
239
        pj_thread_t *rec = (pj_thread_t*)main_thread;
 
240
        PJ_LOG(5,(rec->obj_name, "Main thread stack max usage=%u by %s:%d", 
 
241
                  rec->stk_max_usage, rec->caller_file, rec->caller_line));
 
242
    }
 
243
#endif
 
244
 
 
245
    /* Call atexit() functions */
 
246
    for (i=atexit_count-1; i>=0; --i) {
 
247
        (*atexit_func[i])();
 
248
    }
 
249
    atexit_count = 0;
 
250
 
 
251
    /* Free exception ID */
 
252
    if (PJ_NO_MEMORY_EXCEPTION != -1) {
 
253
        pj_exception_id_free(PJ_NO_MEMORY_EXCEPTION);
 
254
        PJ_NO_MEMORY_EXCEPTION = -1;
 
255
    }
 
256
 
 
257
    /* Destroy PJLIB critical section */
 
258
    pj_mutex_destroy(&critical_section_mutex);
 
259
 
 
260
    /* Free PJLIB TLS */
 
261
    if (thread_tls_id != -1) {
 
262
        pj_thread_local_free(thread_tls_id);
 
263
        thread_tls_id = -1;
 
264
    }
 
265
 
 
266
    /* Clear static variables */
 
267
    pj_errno_clear_handlers();
 
268
 
 
269
    /* Ticket #1132: Assertion when (re)starting PJLIB on different thread */
 
270
    pj_bzero(main_thread, sizeof(main_thread));
 
271
 
 
272
    /* Shutdown Winsock */
 
273
    WSACleanup();
 
274
}
 
275
 
 
276
 
 
277
/*
 
278
 * pj_getpid(void)
 
279
 */
 
280
PJ_DEF(pj_uint32_t) pj_getpid(void)
 
281
{
 
282
    PJ_CHECK_STACK();
 
283
    return GetCurrentProcessId();
 
284
}
 
285
 
 
286
/*
 
287
 * Check if this thread has been registered to PJLIB.
 
288
 */
 
289
PJ_DEF(pj_bool_t) pj_thread_is_registered(void)
 
290
{
 
291
    return pj_thread_local_get(thread_tls_id) != 0;
 
292
}
 
293
 
 
294
 
 
295
/*
 
296
 * Get thread priority value for the thread.
 
297
 */
 
298
PJ_DEF(int) pj_thread_get_prio(pj_thread_t *thread)
 
299
{
 
300
    return GetThreadPriority(thread->hthread);
 
301
}
 
302
 
 
303
 
 
304
/*
 
305
 * Set the thread priority.
 
306
 */
 
307
PJ_DEF(pj_status_t) pj_thread_set_prio(pj_thread_t *thread,  int prio)
 
308
{
 
309
#if PJ_HAS_THREADS
 
310
    PJ_ASSERT_RETURN(thread, PJ_EINVAL);
 
311
    PJ_ASSERT_RETURN(prio>=THREAD_PRIORITY_IDLE && 
 
312
                        prio<=THREAD_PRIORITY_TIME_CRITICAL,
 
313
                     PJ_EINVAL);
 
314
 
 
315
    if (SetThreadPriority(thread->hthread, prio) == FALSE)
 
316
        return PJ_RETURN_OS_ERROR(GetLastError());
 
317
 
 
318
    return PJ_SUCCESS;
 
319
 
 
320
#else
 
321
    PJ_UNUSED_ARG(thread);
 
322
    PJ_UNUSED_ARG(prio);
 
323
    pj_assert("pj_thread_set_prio() called in non-threading mode!");
 
324
    return PJ_EINVALIDOP;
 
325
#endif
 
326
}
 
327
 
 
328
 
 
329
/*
 
330
 * Get the lowest priority value available on this system.
 
331
 */
 
332
PJ_DEF(int) pj_thread_get_prio_min(pj_thread_t *thread)
 
333
{
 
334
    PJ_UNUSED_ARG(thread);
 
335
    return THREAD_PRIORITY_IDLE;
 
336
}
 
337
 
 
338
 
 
339
/*
 
340
 * Get the highest priority value available on this system.
 
341
 */
 
342
PJ_DEF(int) pj_thread_get_prio_max(pj_thread_t *thread)
 
343
{
 
344
    PJ_UNUSED_ARG(thread);
 
345
    return THREAD_PRIORITY_TIME_CRITICAL;
 
346
}
 
347
 
 
348
 
 
349
/*
 
350
 * Get native thread handle
 
351
 */
 
352
PJ_DEF(void*) pj_thread_get_os_handle(pj_thread_t *thread) 
 
353
{
 
354
    PJ_ASSERT_RETURN(thread, NULL);
 
355
 
 
356
#if PJ_HAS_THREADS
 
357
    return thread->hthread;
 
358
#else
 
359
    pj_assert("pj_thread_is_registered() called in non-threading mode!");
 
360
    return NULL;
 
361
#endif
 
362
}
 
363
 
 
364
/*
 
365
 * pj_thread_register(..)
 
366
 */
 
367
PJ_DEF(pj_status_t) pj_thread_register ( const char *cstr_thread_name,
 
368
                                         pj_thread_desc desc,
 
369
                                         pj_thread_t **thread_ptr)
 
370
{
 
371
    char stack_ptr;
 
372
    pj_status_t rc;
 
373
    pj_thread_t *thread = (pj_thread_t *)desc;
 
374
    pj_str_t thread_name = pj_str((char*)cstr_thread_name);
 
375
 
 
376
    /* Size sanity check. */
 
377
    if (sizeof(pj_thread_desc) < sizeof(pj_thread_t)) {
 
378
        pj_assert(!"Not enough pj_thread_desc size!");
 
379
        return PJ_EBUG;
 
380
    }
 
381
 
 
382
    /* If a thread descriptor has been registered before, just return it. */
 
383
    if (pj_thread_local_get (thread_tls_id) != 0) {
 
384
        // 2006-02-26 bennylp:
 
385
        //  This wouldn't work in all cases!.
 
386
        //  If thread is created by external module (e.g. sound thread),
 
387
        //  thread may be reused while the pool used for the thread descriptor
 
388
        //  has been deleted by application.
 
389
        //*thread_ptr = (pj_thread_t*)pj_thread_local_get (thread_tls_id);
 
390
        //return PJ_SUCCESS;
 
391
    }
 
392
 
 
393
    /* Initialize and set the thread entry. */
 
394
    pj_bzero(desc, sizeof(struct pj_thread_t));
 
395
    thread->hthread = GetCurrentThread();
 
396
    thread->idthread = GetCurrentThreadId();
 
397
 
 
398
#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
 
399
    thread->stk_start = &stack_ptr;
 
400
    thread->stk_size = 0xFFFFFFFFUL;
 
401
    thread->stk_max_usage = 0;
 
402
#else
 
403
    stack_ptr = '\0';
 
404
#endif
 
405
 
 
406
    if (cstr_thread_name && pj_strlen(&thread_name) < sizeof(thread->obj_name)-1)
 
407
        pj_ansi_snprintf(thread->obj_name, sizeof(thread->obj_name), 
 
408
                         cstr_thread_name, thread->idthread);
 
409
    else
 
410
        pj_ansi_snprintf(thread->obj_name, sizeof(thread->obj_name), 
 
411
                         "thr%p", (void*)(pj_ssize_t)thread->idthread);
 
412
    
 
413
    rc = pj_thread_local_set(thread_tls_id, thread);
 
414
    if (rc != PJ_SUCCESS)
 
415
        return rc;
 
416
 
 
417
    *thread_ptr = thread;
 
418
    return PJ_SUCCESS;
 
419
}
 
420
 
 
421
/*
 
422
 * pj_thread_init(void)
 
423
 */
 
424
pj_status_t pj_thread_init(void)
 
425
{
 
426
    pj_status_t rc;
 
427
    pj_thread_t *thread;
 
428
 
 
429
    rc = pj_thread_local_alloc(&thread_tls_id);
 
430
    if (rc != PJ_SUCCESS)
 
431
        return rc;
 
432
 
 
433
    return pj_thread_register("thr%p", main_thread, &thread);
 
434
}
 
435
 
 
436
static DWORD WINAPI thread_main(void *param)
 
437
{
 
438
    pj_thread_t *rec = param;
 
439
    DWORD result;
 
440
 
 
441
#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
 
442
    rec->stk_start = (char*)&rec;
 
443
#endif
 
444
 
 
445
    if (pj_thread_local_set(thread_tls_id, rec) != PJ_SUCCESS) {
 
446
        pj_assert(!"TLS is not set (pj_init() error?)");
 
447
    }
 
448
 
 
449
    PJ_LOG(6,(rec->obj_name, "Thread started"));
 
450
 
 
451
    result = (*rec->proc)(rec->arg);
 
452
 
 
453
    PJ_LOG(6,(rec->obj_name, "Thread quitting"));
 
454
#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
 
455
    PJ_LOG(5,(rec->obj_name, "Thread stack max usage=%u by %s:%d", 
 
456
              rec->stk_max_usage, rec->caller_file, rec->caller_line));
 
457
#endif
 
458
 
 
459
    return (DWORD)result;
 
460
}
 
461
 
 
462
/*
 
463
 * pj_thread_create(...)
 
464
 */
 
465
PJ_DEF(pj_status_t) pj_thread_create( pj_pool_t *pool, 
 
466
                                      const char *thread_name,
 
467
                                      pj_thread_proc *proc, 
 
468
                                      void *arg,
 
469
                                      pj_size_t stack_size, 
 
470
                                      unsigned flags,
 
471
                                      pj_thread_t **thread_ptr)
 
472
{
 
473
    DWORD dwflags = 0;
 
474
    pj_thread_t *rec;
 
475
 
 
476
    PJ_CHECK_STACK();
 
477
    PJ_ASSERT_RETURN(pool && proc && thread_ptr, PJ_EINVAL);
 
478
 
 
479
    /* Set flags */
 
480
    if (flags & PJ_THREAD_SUSPENDED)
 
481
        dwflags |= CREATE_SUSPENDED;
 
482
 
 
483
    /* Create thread record and assign name for the thread */
 
484
    rec = (struct pj_thread_t*) pj_pool_calloc(pool, 1, sizeof(pj_thread_t));
 
485
    if (!rec)
 
486
        return PJ_ENOMEM;
 
487
 
 
488
    /* Set name. */
 
489
    if (!thread_name)
 
490
        thread_name = "thr%p";
 
491
 
 
492
    if (strchr(thread_name, '%')) {
 
493
        pj_ansi_snprintf(rec->obj_name, PJ_MAX_OBJ_NAME, thread_name, rec);
 
494
    } else {
 
495
        pj_ansi_strncpy(rec->obj_name, thread_name, PJ_MAX_OBJ_NAME);
 
496
        rec->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
 
497
    }
 
498
 
 
499
    PJ_LOG(6, (rec->obj_name, "Thread created"));
 
500
 
 
501
#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
 
502
    rec->stk_size = stack_size ? (pj_uint32_t)stack_size : 0xFFFFFFFFUL;
 
503
    rec->stk_max_usage = 0;
 
504
#endif
 
505
 
 
506
    /* Create the thread. */
 
507
    rec->proc = proc;
 
508
    rec->arg = arg;
 
509
    rec->hthread = CreateThread(NULL, stack_size, 
 
510
                                thread_main, rec,
 
511
                                dwflags, &rec->idthread);
 
512
    if (rec->hthread == NULL)
 
513
        return PJ_RETURN_OS_ERROR(GetLastError());
 
514
 
 
515
    /* Success! */
 
516
    *thread_ptr = rec;
 
517
    return PJ_SUCCESS;
 
518
}
 
519
 
 
520
/*
 
521
 * pj_thread-get_name()
 
522
 */
 
523
PJ_DEF(const char*) pj_thread_get_name(pj_thread_t *p)
 
524
{
 
525
    pj_thread_t *rec = (pj_thread_t*)p;
 
526
 
 
527
    PJ_CHECK_STACK();
 
528
    PJ_ASSERT_RETURN(p, "");
 
529
 
 
530
    return rec->obj_name;
 
531
}
 
532
 
 
533
/*
 
534
 * pj_thread_resume()
 
535
 */
 
536
PJ_DEF(pj_status_t) pj_thread_resume(pj_thread_t *p)
 
537
{
 
538
    pj_thread_t *rec = (pj_thread_t*)p;
 
539
 
 
540
    PJ_CHECK_STACK();
 
541
    PJ_ASSERT_RETURN(p, PJ_EINVAL);
 
542
 
 
543
    if (ResumeThread(rec->hthread) == (DWORD)-1)
 
544
        return PJ_RETURN_OS_ERROR(GetLastError());
 
545
    else
 
546
        return PJ_SUCCESS;
 
547
}
 
548
 
 
549
/*
 
550
 * pj_thread_this()
 
551
 */
 
552
PJ_DEF(pj_thread_t*) pj_thread_this(void)
 
553
{
 
554
    pj_thread_t *rec = pj_thread_local_get(thread_tls_id);
 
555
 
 
556
    if (rec == NULL) {
 
557
        pj_assert(!"Calling pjlib from unknown/external thread. You must "
 
558
                   "register external threads with pj_thread_register() "
 
559
                   "before calling any pjlib functions.");
 
560
    }
 
561
 
 
562
    /*
 
563
     * MUST NOT check stack because this function is called
 
564
     * by PJ_CHECK_STACK() itself!!!
 
565
     *
 
566
     */
 
567
 
 
568
    return rec;
 
569
}
 
570
 
 
571
/*
 
572
 * pj_thread_join()
 
573
 */
 
574
PJ_DEF(pj_status_t) pj_thread_join(pj_thread_t *p)
 
575
{
 
576
    pj_thread_t *rec = (pj_thread_t *)p;
 
577
    DWORD rc;
 
578
 
 
579
    PJ_CHECK_STACK();
 
580
    PJ_ASSERT_RETURN(p, PJ_EINVAL);
 
581
 
 
582
    if (p == pj_thread_this())
 
583
        return PJ_ECANCELLED;
 
584
 
 
585
    PJ_LOG(6, (pj_thread_this()->obj_name, "Joining thread %s", p->obj_name));
 
586
 
 
587
    rc = WaitForSingleObject(rec->hthread, INFINITE);
 
588
 
 
589
    if (rc==WAIT_OBJECT_0)
 
590
        return PJ_SUCCESS;
 
591
    else if (rc==WAIT_TIMEOUT)
 
592
        return PJ_ETIMEDOUT;
 
593
    else
 
594
        return PJ_RETURN_OS_ERROR(GetLastError());
 
595
}
 
596
 
 
597
/*
 
598
 * pj_thread_destroy()
 
599
 */
 
600
PJ_DEF(pj_status_t) pj_thread_destroy(pj_thread_t *p)
 
601
{
 
602
    pj_thread_t *rec = (pj_thread_t *)p;
 
603
 
 
604
    PJ_CHECK_STACK();
 
605
    PJ_ASSERT_RETURN(p, PJ_EINVAL);
 
606
 
 
607
    if (CloseHandle(rec->hthread) == TRUE)
 
608
        return PJ_SUCCESS;
 
609
    else
 
610
        return PJ_RETURN_OS_ERROR(GetLastError());
 
611
}
 
612
 
 
613
/*
 
614
 * pj_thread_sleep()
 
615
 */
 
616
PJ_DEF(pj_status_t) pj_thread_sleep(unsigned msec)
 
617
{
 
618
    PJ_CHECK_STACK();
 
619
    Sleep(msec);
 
620
    return PJ_SUCCESS;
 
621
}
 
622
 
 
623
#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK != 0
 
624
/*
 
625
 * pj_thread_check_stack()
 
626
 * Implementation for PJ_CHECK_STACK()
 
627
 */
 
628
PJ_DEF(void) pj_thread_check_stack(const char *file, int line)
 
629
{
 
630
    char stk_ptr;
 
631
    pj_uint32_t usage;
 
632
    pj_thread_t *thread = pj_thread_this();
 
633
 
 
634
    pj_assert(thread);
 
635
 
 
636
    /* Calculate current usage. */
 
637
    usage = (&stk_ptr > thread->stk_start) ? 
 
638
                (pj_uint32_t)(&stk_ptr - thread->stk_start) :
 
639
                (pj_uint32_t)(thread->stk_start - &stk_ptr);
 
640
 
 
641
    /* Assert if stack usage is dangerously high. */
 
642
    pj_assert("STACK OVERFLOW!! " && (usage <= thread->stk_size - 128));
 
643
 
 
644
    /* Keep statistic. */
 
645
    if (usage > thread->stk_max_usage) {
 
646
        thread->stk_max_usage = usage;
 
647
        thread->caller_file = file;
 
648
        thread->caller_line = line;
 
649
    }
 
650
 
 
651
}
 
652
 
 
653
/*
 
654
 * pj_thread_get_stack_max_usage()
 
655
 */
 
656
PJ_DEF(pj_uint32_t) pj_thread_get_stack_max_usage(pj_thread_t *thread)
 
657
{
 
658
    return thread->stk_max_usage;
 
659
}
 
660
 
 
661
/*
 
662
 * pj_thread_get_stack_info()
 
663
 */
 
664
PJ_DEF(pj_status_t) pj_thread_get_stack_info( pj_thread_t *thread,
 
665
                                              const char **file,
 
666
                                              int *line )
 
667
{
 
668
    pj_assert(thread);
 
669
 
 
670
    *file = thread->caller_file;
 
671
    *line = thread->caller_line;
 
672
    return 0;
 
673
}
 
674
 
 
675
#endif  /* PJ_OS_HAS_CHECK_STACK */
 
676
 
 
677
 
 
678
///////////////////////////////////////////////////////////////////////////////
 
679
 
 
680
/*
 
681
 * pj_atomic_create()
 
682
 */
 
683
PJ_DEF(pj_status_t) pj_atomic_create( pj_pool_t *pool, 
 
684
                                      pj_atomic_value_t initial,
 
685
                                      pj_atomic_t **atomic_ptr)
 
686
{
 
687
    pj_atomic_t *atomic_var = pj_pool_alloc(pool, sizeof(pj_atomic_t));
 
688
    if (!atomic_var)
 
689
        return PJ_ENOMEM;
 
690
 
 
691
    atomic_var->value = initial;
 
692
    *atomic_ptr = atomic_var;
 
693
 
 
694
    return PJ_SUCCESS;
 
695
}
 
696
 
 
697
/*
 
698
 * pj_atomic_destroy()
 
699
 */
 
700
PJ_DEF(pj_status_t) pj_atomic_destroy( pj_atomic_t *var )
 
701
{
 
702
    PJ_UNUSED_ARG(var);
 
703
    PJ_ASSERT_RETURN(var, PJ_EINVAL);
 
704
 
 
705
    return 0;
 
706
}
 
707
 
 
708
/*
 
709
 * pj_atomic_set()
 
710
 */
 
711
PJ_DEF(void) pj_atomic_set( pj_atomic_t *atomic_var, pj_atomic_value_t value)
 
712
{
 
713
    PJ_CHECK_STACK();
 
714
 
 
715
    InterlockedExchange(&atomic_var->value, value);
 
716
}
 
717
 
 
718
/*
 
719
 * pj_atomic_get()
 
720
 */
 
721
PJ_DEF(pj_atomic_value_t) pj_atomic_get(pj_atomic_t *atomic_var)
 
722
{
 
723
    PJ_CHECK_STACK();
 
724
    PJ_ASSERT_RETURN(atomic_var, 0);
 
725
 
 
726
    return atomic_var->value;
 
727
}
 
728
 
 
729
/*
 
730
 * pj_atomic_inc_and_get()
 
731
 */
 
732
PJ_DEF(pj_atomic_value_t) pj_atomic_inc_and_get(pj_atomic_t *atomic_var)
 
733
{
 
734
    PJ_CHECK_STACK();
 
735
 
 
736
#if defined(PJ_WIN32_WINNT) && PJ_WIN32_WINNT >= 0x0400
 
737
    return InterlockedIncrement(&atomic_var->value);
 
738
#else
 
739
    return InterlockedIncrement(&atomic_var->value);
 
740
#endif
 
741
}
 
742
 
 
743
/*
 
744
 * pj_atomic_inc()
 
745
 */
 
746
PJ_DEF(void) pj_atomic_inc(pj_atomic_t *atomic_var)
 
747
{
 
748
    pj_atomic_inc_and_get(atomic_var);
 
749
}
 
750
 
 
751
/*
 
752
 * pj_atomic_dec_and_get()
 
753
 */
 
754
PJ_DEF(pj_atomic_value_t) pj_atomic_dec_and_get(pj_atomic_t *atomic_var)
 
755
{
 
756
    PJ_CHECK_STACK();
 
757
 
 
758
#if defined(PJ_WIN32_WINNT) && PJ_WIN32_WINNT >= 0x0400
 
759
    return InterlockedDecrement(&atomic_var->value);
 
760
#else
 
761
    return InterlockedDecrement(&atomic_var->value);
 
762
#endif
 
763
}
 
764
 
 
765
/*
 
766
 * pj_atomic_dec()
 
767
 */
 
768
PJ_DEF(void) pj_atomic_dec(pj_atomic_t *atomic_var)
 
769
{
 
770
    pj_atomic_dec_and_get(atomic_var);
 
771
}
 
772
 
 
773
/*
 
774
 * pj_atomic_add()
 
775
 */
 
776
PJ_DEF(void) pj_atomic_add( pj_atomic_t *atomic_var,
 
777
                            pj_atomic_value_t value )
 
778
{
 
779
#if defined(PJ_WIN32_WINNT) && PJ_WIN32_WINNT >= 0x0400
 
780
    InterlockedExchangeAdd( &atomic_var->value, value );
 
781
#else
 
782
    InterlockedExchangeAdd( &atomic_var->value, value );
 
783
#endif
 
784
}
 
785
 
 
786
/*
 
787
 * pj_atomic_add_and_get()
 
788
 */
 
789
PJ_DEF(pj_atomic_value_t) pj_atomic_add_and_get( pj_atomic_t *atomic_var,
 
790
                                                 pj_atomic_value_t value)
 
791
{
 
792
#if defined(PJ_WIN32_WINNT) && PJ_WIN32_WINNT >= 0x0400
 
793
    long oldValue = InterlockedExchangeAdd( &atomic_var->value, value);
 
794
    return oldValue + value;
 
795
#else
 
796
    long oldValue = InterlockedExchangeAdd( &atomic_var->value, value);
 
797
    return oldValue + value;
 
798
#endif
 
799
}
 
800
 
 
801
///////////////////////////////////////////////////////////////////////////////
 
802
/*
 
803
 * pj_thread_local_alloc()
 
804
 */
 
805
PJ_DEF(pj_status_t) pj_thread_local_alloc(long *index)
 
806
{
 
807
    PJ_ASSERT_RETURN(index != NULL, PJ_EINVAL);
 
808
 
 
809
    //Can't check stack because this function is called in the
 
810
    //beginning before main thread is initialized.
 
811
    //PJ_CHECK_STACK();
 
812
 
 
813
    *index = TlsAlloc();
 
814
 
 
815
    if (*index == TLS_OUT_OF_INDEXES)
 
816
        return PJ_RETURN_OS_ERROR(GetLastError());
 
817
    else
 
818
        return PJ_SUCCESS;
 
819
}
 
820
 
 
821
/*
 
822
 * pj_thread_local_free()
 
823
 */
 
824
PJ_DEF(void) pj_thread_local_free(long index)
 
825
{
 
826
    PJ_CHECK_STACK();
 
827
    TlsFree(index);
 
828
}
 
829
 
 
830
/*
 
831
 * pj_thread_local_set()
 
832
 */
 
833
PJ_DEF(pj_status_t) pj_thread_local_set(long index, void *value)
 
834
{
 
835
    BOOL rc;
 
836
 
 
837
    //Can't check stack because this function is called in the
 
838
    //beginning before main thread is initialized.
 
839
    //PJ_CHECK_STACK();
 
840
    rc = TlsSetValue(index, value);
 
841
    return rc!=0 ? PJ_SUCCESS : PJ_RETURN_OS_ERROR(GetLastError());
 
842
}
 
843
 
 
844
/*
 
845
 * pj_thread_local_get()
 
846
 */
 
847
PJ_DEF(void*) pj_thread_local_get(long index)
 
848
{
 
849
    //Can't check stack because this function is called
 
850
    //by PJ_CHECK_STACK() itself!!!
 
851
    //PJ_CHECK_STACK();
 
852
    return TlsGetValue(index);
 
853
}
 
854
 
 
855
///////////////////////////////////////////////////////////////////////////////
 
856
static pj_status_t init_mutex(pj_mutex_t *mutex, const char *name)
 
857
{
 
858
 
 
859
    PJ_CHECK_STACK();
 
860
 
 
861
#if PJ_WIN32_WINNT >= 0x0400
 
862
    InitializeCriticalSection(&mutex->crit);
 
863
#else
 
864
    mutex->hMutex = CreateMutex(NULL, FALSE, NULL);
 
865
    if (!mutex->hMutex) {
 
866
        return PJ_RETURN_OS_ERROR(GetLastError());
 
867
    }
 
868
#endif
 
869
 
 
870
#if PJ_DEBUG
 
871
    /* Set owner. */
 
872
    mutex->nesting_level = 0;
 
873
    mutex->owner = NULL;
 
874
#endif
 
875
 
 
876
    /* Set name. */
 
877
    if (!name) {
 
878
        name = "mtx%p";
 
879
    }
 
880
    if (strchr(name, '%')) {
 
881
        pj_ansi_snprintf(mutex->obj_name, PJ_MAX_OBJ_NAME, name, mutex);
 
882
    } else {
 
883
        pj_ansi_strncpy(mutex->obj_name, name, PJ_MAX_OBJ_NAME);
 
884
        mutex->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
 
885
    }
 
886
 
 
887
    PJ_LOG(6, (mutex->obj_name, "Mutex created"));
 
888
    return PJ_SUCCESS;
 
889
}
 
890
 
 
891
/*
 
892
 * pj_mutex_create()
 
893
 */
 
894
PJ_DEF(pj_status_t) pj_mutex_create(pj_pool_t *pool, 
 
895
                                    const char *name, 
 
896
                                    int type,
 
897
                                    pj_mutex_t **mutex_ptr)
 
898
{
 
899
    pj_status_t rc;
 
900
    pj_mutex_t *mutex;
 
901
 
 
902
    PJ_UNUSED_ARG(type);
 
903
    PJ_ASSERT_RETURN(pool && mutex_ptr, PJ_EINVAL);
 
904
 
 
905
    mutex = pj_pool_alloc(pool, sizeof(*mutex));
 
906
    if (!mutex)
 
907
        return PJ_ENOMEM;
 
908
 
 
909
    rc = init_mutex(mutex, name);
 
910
    if (rc != PJ_SUCCESS)
 
911
        return rc;
 
912
 
 
913
    *mutex_ptr = mutex;
 
914
 
 
915
    return PJ_SUCCESS;
 
916
}
 
917
 
 
918
/*
 
919
 * pj_mutex_create_simple()
 
920
 */
 
921
PJ_DEF(pj_status_t) pj_mutex_create_simple( pj_pool_t *pool, 
 
922
                                            const char *name,
 
923
                                            pj_mutex_t **mutex )
 
924
{
 
925
    return pj_mutex_create(pool, name, PJ_MUTEX_SIMPLE, mutex);
 
926
}
 
927
 
 
928
/*
 
929
 * pj_mutex_create_recursive()
 
930
 */
 
931
PJ_DEF(pj_status_t) pj_mutex_create_recursive( pj_pool_t *pool,
 
932
                                               const char *name,
 
933
                                               pj_mutex_t **mutex )
 
934
{
 
935
    return pj_mutex_create(pool, name, PJ_MUTEX_RECURSE, mutex);
 
936
}
 
937
 
 
938
/*
 
939
 * pj_mutex_lock()
 
940
 */
 
941
PJ_DEF(pj_status_t) pj_mutex_lock(pj_mutex_t *mutex)
 
942
{
 
943
    pj_status_t status;
 
944
 
 
945
    PJ_CHECK_STACK();
 
946
    PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
 
947
 
 
948
    LOG_MUTEX((mutex->obj_name, "Mutex: thread %s is waiting", 
 
949
                                pj_thread_this()->obj_name));
 
950
 
 
951
#if PJ_WIN32_WINNT >= 0x0400
 
952
    EnterCriticalSection(&mutex->crit);
 
953
    status=PJ_SUCCESS;
 
954
#else
 
955
    if (WaitForSingleObject(mutex->hMutex, INFINITE)==WAIT_OBJECT_0)
 
956
        status = PJ_SUCCESS;
 
957
    else
 
958
        status = PJ_STATUS_FROM_OS(GetLastError());
 
959
 
 
960
#endif
 
961
    LOG_MUTEX((mutex->obj_name, 
 
962
              (status==PJ_SUCCESS ? "Mutex acquired by thread %s" : "FAILED by %s"),
 
963
              pj_thread_this()->obj_name));
 
964
 
 
965
#if PJ_DEBUG
 
966
    if (status == PJ_SUCCESS) {
 
967
        mutex->owner = pj_thread_this();
 
968
        ++mutex->nesting_level;
 
969
    }
 
970
#endif
 
971
 
 
972
    return status;
 
973
}
 
974
 
 
975
/*
 
976
 * pj_mutex_unlock()
 
977
 */
 
978
PJ_DEF(pj_status_t) pj_mutex_unlock(pj_mutex_t *mutex)
 
979
{
 
980
    pj_status_t status;
 
981
 
 
982
    PJ_CHECK_STACK();
 
983
    PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
 
984
 
 
985
#if PJ_DEBUG
 
986
    pj_assert(mutex->owner == pj_thread_this());
 
987
    if (--mutex->nesting_level == 0) {
 
988
        mutex->owner = NULL;
 
989
    }
 
990
#endif
 
991
 
 
992
    LOG_MUTEX((mutex->obj_name, "Mutex released by thread %s", 
 
993
                                pj_thread_this()->obj_name));
 
994
 
 
995
#if PJ_WIN32_WINNT >= 0x0400
 
996
    LeaveCriticalSection(&mutex->crit);
 
997
    status=PJ_SUCCESS;
 
998
#else
 
999
    status = ReleaseMutex(mutex->hMutex) ? PJ_SUCCESS : 
 
1000
                PJ_STATUS_FROM_OS(GetLastError());
 
1001
#endif
 
1002
    return status;
 
1003
}
 
1004
 
 
1005
/*
 
1006
 * pj_mutex_trylock()
 
1007
 */
 
1008
PJ_DEF(pj_status_t) pj_mutex_trylock(pj_mutex_t *mutex)
 
1009
{
 
1010
    pj_status_t status;
 
1011
 
 
1012
    PJ_CHECK_STACK();
 
1013
    PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
 
1014
 
 
1015
    LOG_MUTEX((mutex->obj_name, "Mutex: thread %s is trying", 
 
1016
                                pj_thread_this()->obj_name));
 
1017
 
 
1018
#if PJ_WIN32_WINNT >= 0x0400
 
1019
    status=TryEnterCriticalSection(&mutex->crit) ? PJ_SUCCESS : PJ_EUNKNOWN;
 
1020
#else
 
1021
    status = WaitForSingleObject(mutex->hMutex, 0)==WAIT_OBJECT_0 ? 
 
1022
                PJ_SUCCESS : PJ_ETIMEDOUT;
 
1023
#endif
 
1024
    if (status==PJ_SUCCESS) {
 
1025
        LOG_MUTEX((mutex->obj_name, "Mutex acquired by thread %s", 
 
1026
                                  pj_thread_this()->obj_name));
 
1027
 
 
1028
#if PJ_DEBUG
 
1029
        mutex->owner = pj_thread_this();
 
1030
        ++mutex->nesting_level;
 
1031
#endif
 
1032
    } else {
 
1033
        LOG_MUTEX((mutex->obj_name, "Mutex: thread %s's trylock() failed", 
 
1034
                                    pj_thread_this()->obj_name));
 
1035
    }
 
1036
 
 
1037
    return status;
 
1038
}
 
1039
 
 
1040
/*
 
1041
 * pj_mutex_destroy()
 
1042
 */
 
1043
PJ_DEF(pj_status_t) pj_mutex_destroy(pj_mutex_t *mutex)
 
1044
{
 
1045
    PJ_CHECK_STACK();
 
1046
    PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
 
1047
 
 
1048
    LOG_MUTEX((mutex->obj_name, "Mutex destroyed"));
 
1049
 
 
1050
#if PJ_WIN32_WINNT >= 0x0400
 
1051
    DeleteCriticalSection(&mutex->crit);
 
1052
    return PJ_SUCCESS;
 
1053
#else
 
1054
    return CloseHandle(mutex->hMutex) ? PJ_SUCCESS : 
 
1055
            PJ_RETURN_OS_ERROR(GetLastError());
 
1056
#endif
 
1057
}
 
1058
 
 
1059
/*
 
1060
 * pj_mutex_is_locked()
 
1061
 */
 
1062
PJ_DEF(pj_bool_t) pj_mutex_is_locked(pj_mutex_t *mutex)
 
1063
{
 
1064
#if PJ_DEBUG
 
1065
    return mutex->owner == pj_thread_this();
 
1066
#else
 
1067
    PJ_UNUSED_ARG(mutex);
 
1068
    pj_assert(!"PJ_DEBUG is not set!");
 
1069
    return 1;
 
1070
#endif
 
1071
}
 
1072
 
 
1073
///////////////////////////////////////////////////////////////////////////////
 
1074
/*
 
1075
 * Win32 lacks Read/Write mutex, so include the emulation.
 
1076
 */
 
1077
#include "os_rwmutex.c"
 
1078
 
 
1079
///////////////////////////////////////////////////////////////////////////////
 
1080
/*
 
1081
 * pj_enter_critical_section()
 
1082
 */
 
1083
PJ_DEF(void) pj_enter_critical_section(void)
 
1084
{
 
1085
    pj_mutex_lock(&critical_section_mutex);
 
1086
}
 
1087
 
 
1088
 
 
1089
/*
 
1090
 * pj_leave_critical_section()
 
1091
 */
 
1092
PJ_DEF(void) pj_leave_critical_section(void)
 
1093
{
 
1094
    pj_mutex_unlock(&critical_section_mutex);
 
1095
}
 
1096
 
 
1097
///////////////////////////////////////////////////////////////////////////////
 
1098
#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0
 
1099
 
 
1100
/*
 
1101
 * pj_sem_create()
 
1102
 */
 
1103
PJ_DEF(pj_status_t) pj_sem_create( pj_pool_t *pool, 
 
1104
                                   const char *name,
 
1105
                                   unsigned initial, 
 
1106
                                   unsigned max,
 
1107
                                   pj_sem_t **sem_ptr)
 
1108
{
 
1109
    pj_sem_t *sem;
 
1110
 
 
1111
    PJ_CHECK_STACK();
 
1112
    PJ_ASSERT_RETURN(pool && sem_ptr, PJ_EINVAL);
 
1113
 
 
1114
    sem = pj_pool_alloc(pool, sizeof(*sem));    
 
1115
    sem->hSemaphore = CreateSemaphore(NULL, initial, max, NULL);
 
1116
    if (!sem->hSemaphore)
 
1117
        return PJ_RETURN_OS_ERROR(GetLastError());
 
1118
 
 
1119
    /* Set name. */
 
1120
    if (!name) {
 
1121
        name = "sem%p";
 
1122
    }
 
1123
    if (strchr(name, '%')) {
 
1124
        pj_ansi_snprintf(sem->obj_name, PJ_MAX_OBJ_NAME, name, sem);
 
1125
    } else {
 
1126
        pj_ansi_strncpy(sem->obj_name, name, PJ_MAX_OBJ_NAME);
 
1127
        sem->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
 
1128
    }
 
1129
 
 
1130
    LOG_MUTEX((sem->obj_name, "Semaphore created"));
 
1131
 
 
1132
    *sem_ptr = sem;
 
1133
    return PJ_SUCCESS;
 
1134
}
 
1135
 
 
1136
static pj_status_t pj_sem_wait_for(pj_sem_t *sem, unsigned timeout)
 
1137
{
 
1138
    DWORD result;
 
1139
 
 
1140
    PJ_CHECK_STACK();
 
1141
    PJ_ASSERT_RETURN(sem, PJ_EINVAL);
 
1142
 
 
1143
    LOG_MUTEX((sem->obj_name, "Semaphore: thread %s is waiting", 
 
1144
                              pj_thread_this()->obj_name));
 
1145
 
 
1146
    result = WaitForSingleObject(sem->hSemaphore, timeout);
 
1147
    if (result == WAIT_OBJECT_0) {
 
1148
        LOG_MUTEX((sem->obj_name, "Semaphore acquired by thread %s", 
 
1149
                                  pj_thread_this()->obj_name));
 
1150
    } else {
 
1151
        LOG_MUTEX((sem->obj_name, "Semaphore: thread %s FAILED to acquire", 
 
1152
                                  pj_thread_this()->obj_name));
 
1153
    }
 
1154
 
 
1155
    if (result==WAIT_OBJECT_0)
 
1156
        return PJ_SUCCESS;
 
1157
    else if (result==WAIT_TIMEOUT)
 
1158
        return PJ_ETIMEDOUT;
 
1159
    else
 
1160
        return PJ_RETURN_OS_ERROR(GetLastError());
 
1161
}
 
1162
 
 
1163
/*
 
1164
 * pj_sem_wait()
 
1165
 */
 
1166
PJ_DEF(pj_status_t) pj_sem_wait(pj_sem_t *sem)
 
1167
{
 
1168
    PJ_CHECK_STACK();
 
1169
    PJ_ASSERT_RETURN(sem, PJ_EINVAL);
 
1170
 
 
1171
    return pj_sem_wait_for(sem, INFINITE);
 
1172
}
 
1173
 
 
1174
/*
 
1175
 * pj_sem_trywait()
 
1176
 */
 
1177
PJ_DEF(pj_status_t) pj_sem_trywait(pj_sem_t *sem)
 
1178
{
 
1179
    PJ_CHECK_STACK();
 
1180
    PJ_ASSERT_RETURN(sem, PJ_EINVAL);
 
1181
 
 
1182
    return pj_sem_wait_for(sem, 0);
 
1183
}
 
1184
 
 
1185
/*
 
1186
 * pj_sem_post()
 
1187
 */
 
1188
PJ_DEF(pj_status_t) pj_sem_post(pj_sem_t *sem)
 
1189
{
 
1190
    PJ_CHECK_STACK();
 
1191
    PJ_ASSERT_RETURN(sem, PJ_EINVAL);
 
1192
 
 
1193
    LOG_MUTEX((sem->obj_name, "Semaphore released by thread %s",
 
1194
                              pj_thread_this()->obj_name));
 
1195
 
 
1196
    if (ReleaseSemaphore(sem->hSemaphore, 1, NULL))
 
1197
        return PJ_SUCCESS;
 
1198
    else
 
1199
        return PJ_RETURN_OS_ERROR(GetLastError());
 
1200
}
 
1201
 
 
1202
/*
 
1203
 * pj_sem_destroy()
 
1204
 */
 
1205
PJ_DEF(pj_status_t) pj_sem_destroy(pj_sem_t *sem)
 
1206
{
 
1207
    PJ_CHECK_STACK();
 
1208
    PJ_ASSERT_RETURN(sem, PJ_EINVAL);
 
1209
 
 
1210
    LOG_MUTEX((sem->obj_name, "Semaphore destroyed by thread %s",
 
1211
                              pj_thread_this()->obj_name));
 
1212
 
 
1213
    if (CloseHandle(sem->hSemaphore))
 
1214
        return PJ_SUCCESS;
 
1215
    else
 
1216
        return PJ_RETURN_OS_ERROR(GetLastError());
 
1217
}
 
1218
 
 
1219
#endif  /* PJ_HAS_SEMAPHORE */
 
1220
///////////////////////////////////////////////////////////////////////////////
 
1221
 
 
1222
 
 
1223
#if defined(PJ_HAS_EVENT_OBJ) && PJ_HAS_EVENT_OBJ != 0
 
1224
 
 
1225
/*
 
1226
 * pj_event_create()
 
1227
 */
 
1228
PJ_DEF(pj_status_t) pj_event_create( pj_pool_t *pool, 
 
1229
                                     const char *name,
 
1230
                                     pj_bool_t manual_reset, 
 
1231
                                     pj_bool_t initial,
 
1232
                                     pj_event_t **event_ptr)
 
1233
{
 
1234
    pj_event_t *event;
 
1235
 
 
1236
    PJ_CHECK_STACK();
 
1237
    PJ_ASSERT_RETURN(pool && event_ptr, PJ_EINVAL);
 
1238
 
 
1239
    event = pj_pool_alloc(pool, sizeof(*event));
 
1240
    if (!event)
 
1241
        return PJ_ENOMEM;
 
1242
 
 
1243
    event->hEvent = CreateEvent(NULL, manual_reset?TRUE:FALSE, 
 
1244
                                initial?TRUE:FALSE, NULL);
 
1245
 
 
1246
    if (!event->hEvent)
 
1247
        return PJ_RETURN_OS_ERROR(GetLastError());
 
1248
 
 
1249
    /* Set name. */
 
1250
    if (!name) {
 
1251
        name = "evt%p";
 
1252
    }
 
1253
    if (strchr(name, '%')) {
 
1254
        pj_ansi_snprintf(event->obj_name, PJ_MAX_OBJ_NAME, name, event);
 
1255
    } else {
 
1256
        pj_ansi_strncpy(event->obj_name, name, PJ_MAX_OBJ_NAME);
 
1257
        event->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
 
1258
    }
 
1259
 
 
1260
    PJ_LOG(6, (event->obj_name, "Event created"));
 
1261
 
 
1262
    *event_ptr = event;
 
1263
    return PJ_SUCCESS;
 
1264
}
 
1265
 
 
1266
static pj_status_t pj_event_wait_for(pj_event_t *event, unsigned timeout)
 
1267
{
 
1268
    DWORD result;
 
1269
 
 
1270
    PJ_CHECK_STACK();
 
1271
    PJ_ASSERT_RETURN(event, PJ_EINVAL);
 
1272
 
 
1273
    PJ_LOG(6, (event->obj_name, "Event: thread %s is waiting", 
 
1274
                                pj_thread_this()->obj_name));
 
1275
 
 
1276
    result = WaitForSingleObject(event->hEvent, timeout);
 
1277
    if (result == WAIT_OBJECT_0) {
 
1278
        PJ_LOG(6, (event->obj_name, "Event: thread %s is released", 
 
1279
                                    pj_thread_this()->obj_name));
 
1280
    } else {
 
1281
        PJ_LOG(6, (event->obj_name, "Event: thread %s FAILED to acquire", 
 
1282
                                    pj_thread_this()->obj_name));
 
1283
    }
 
1284
 
 
1285
    if (result==WAIT_OBJECT_0)
 
1286
        return PJ_SUCCESS;
 
1287
    else if (result==WAIT_TIMEOUT)
 
1288
        return PJ_ETIMEDOUT;
 
1289
    else
 
1290
        return PJ_RETURN_OS_ERROR(GetLastError());
 
1291
}
 
1292
 
 
1293
/*
 
1294
 * pj_event_wait()
 
1295
 */
 
1296
PJ_DEF(pj_status_t) pj_event_wait(pj_event_t *event)
 
1297
{
 
1298
    PJ_ASSERT_RETURN(event, PJ_EINVAL);
 
1299
 
 
1300
    return pj_event_wait_for(event, INFINITE);
 
1301
}
 
1302
 
 
1303
/*
 
1304
 * pj_event_trywait()
 
1305
 */
 
1306
PJ_DEF(pj_status_t) pj_event_trywait(pj_event_t *event)
 
1307
{
 
1308
    PJ_ASSERT_RETURN(event, PJ_EINVAL);
 
1309
 
 
1310
    return pj_event_wait_for(event, 0);
 
1311
}
 
1312
 
 
1313
/*
 
1314
 * pj_event_set()
 
1315
 */
 
1316
PJ_DEF(pj_status_t) pj_event_set(pj_event_t *event)
 
1317
{
 
1318
    PJ_CHECK_STACK();
 
1319
    PJ_ASSERT_RETURN(event, PJ_EINVAL);
 
1320
 
 
1321
    PJ_LOG(6, (event->obj_name, "Setting event"));
 
1322
 
 
1323
    if (SetEvent(event->hEvent))
 
1324
        return PJ_SUCCESS;
 
1325
    else
 
1326
        return PJ_RETURN_OS_ERROR(GetLastError());
 
1327
}
 
1328
 
 
1329
/*
 
1330
 * pj_event_pulse()
 
1331
 */
 
1332
PJ_DEF(pj_status_t) pj_event_pulse(pj_event_t *event)
 
1333
{
 
1334
    PJ_CHECK_STACK();
 
1335
    PJ_ASSERT_RETURN(event, PJ_EINVAL);
 
1336
 
 
1337
    PJ_LOG(6, (event->obj_name, "Pulsing event"));
 
1338
 
 
1339
    if (PulseEvent(event->hEvent))
 
1340
        return PJ_SUCCESS;
 
1341
    else
 
1342
        return PJ_RETURN_OS_ERROR(GetLastError());
 
1343
}
 
1344
 
 
1345
/*
 
1346
 * pj_event_reset()
 
1347
 */
 
1348
PJ_DEF(pj_status_t) pj_event_reset(pj_event_t *event)
 
1349
{
 
1350
    PJ_CHECK_STACK();
 
1351
    PJ_ASSERT_RETURN(event, PJ_EINVAL);
 
1352
 
 
1353
    PJ_LOG(6, (event->obj_name, "Event is reset"));
 
1354
 
 
1355
    if (ResetEvent(event->hEvent))
 
1356
        return PJ_SUCCESS;
 
1357
    else
 
1358
        return PJ_RETURN_OS_ERROR(GetLastError());
 
1359
}
 
1360
 
 
1361
/*
 
1362
 * pj_event_destroy()
 
1363
 */
 
1364
PJ_DEF(pj_status_t) pj_event_destroy(pj_event_t *event)
 
1365
{
 
1366
    PJ_CHECK_STACK();
 
1367
    PJ_ASSERT_RETURN(event, PJ_EINVAL);
 
1368
 
 
1369
    PJ_LOG(6, (event->obj_name, "Event is destroying"));
 
1370
 
 
1371
    if (CloseHandle(event->hEvent))
 
1372
        return PJ_SUCCESS;
 
1373
    else
 
1374
        return PJ_RETURN_OS_ERROR(GetLastError());
 
1375
}
 
1376
 
 
1377
#endif  /* PJ_HAS_EVENT_OBJ */
 
1378
 
 
1379
///////////////////////////////////////////////////////////////////////////////
 
1380
#if defined(PJ_TERM_HAS_COLOR) && PJ_TERM_HAS_COLOR != 0
 
1381
/*
 
1382
 * Terminal color
 
1383
 */
 
1384
 
 
1385
static WORD pj_color_to_os_attr(pj_color_t color)
 
1386
{
 
1387
    WORD attr = 0;
 
1388
 
 
1389
    if (color & PJ_TERM_COLOR_R)
 
1390
        attr |= FOREGROUND_RED;
 
1391
    if (color & PJ_TERM_COLOR_G)
 
1392
        attr |= FOREGROUND_GREEN;
 
1393
    if (color & PJ_TERM_COLOR_B)
 
1394
        attr |= FOREGROUND_BLUE;
 
1395
    if (color & PJ_TERM_COLOR_BRIGHT)
 
1396
        attr |= FOREGROUND_INTENSITY;
 
1397
 
 
1398
    return attr;
 
1399
}
 
1400
 
 
1401
static pj_color_t os_attr_to_pj_color(WORD attr)
 
1402
{
 
1403
    int color = 0;
 
1404
 
 
1405
    if (attr & FOREGROUND_RED)
 
1406
        color |= PJ_TERM_COLOR_R;
 
1407
    if (attr & FOREGROUND_GREEN)
 
1408
        color |= PJ_TERM_COLOR_G;
 
1409
    if (attr & FOREGROUND_BLUE)
 
1410
        color |= PJ_TERM_COLOR_B;
 
1411
    if (attr & FOREGROUND_INTENSITY)
 
1412
        color |= PJ_TERM_COLOR_BRIGHT;
 
1413
 
 
1414
    return color;
 
1415
}
 
1416
 
 
1417
 
 
1418
/*
 
1419
 * pj_term_set_color()
 
1420
 */
 
1421
PJ_DEF(pj_status_t) pj_term_set_color(pj_color_t color)
 
1422
{
 
1423
    BOOL rc;
 
1424
    WORD attr = 0;
 
1425
 
 
1426
    PJ_CHECK_STACK();
 
1427
 
 
1428
    attr = pj_color_to_os_attr(color);
 
1429
    rc = SetConsoleTextAttribute( GetStdHandle(STD_OUTPUT_HANDLE), attr);
 
1430
    return rc ? PJ_SUCCESS : PJ_RETURN_OS_ERROR(GetLastError());
 
1431
}
 
1432
 
 
1433
/*
 
1434
 * pj_term_get_color()
 
1435
 * Get current terminal foreground color.
 
1436
 */
 
1437
PJ_DEF(pj_color_t) pj_term_get_color(void)
 
1438
{
 
1439
    CONSOLE_SCREEN_BUFFER_INFO info;
 
1440
 
 
1441
    PJ_CHECK_STACK();
 
1442
 
 
1443
    GetConsoleScreenBufferInfo( GetStdHandle(STD_OUTPUT_HANDLE), &info);
 
1444
    return os_attr_to_pj_color(info.wAttributes);
 
1445
}
 
1446
 
 
1447
#endif  /* PJ_TERM_HAS_COLOR */
 
1448
 
 
1449
/*
 
1450
 * pj_run_app()
 
1451
 */
 
1452
PJ_DEF(int) pj_run_app(pj_main_func_ptr main_func, int argc, char *argv[],
 
1453
                       unsigned flags)
 
1454
{
 
1455
    PJ_UNUSED_ARG(flags);
 
1456
    return (*main_func)(argc, argv);
 
1457
}