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

« back to all changes in this revision

Viewing changes to daemon/libs/pjproject-2.1.0/pjlib/src/pj/os_core_unix.c

  • Committer: Package Import Robot
  • Author(s): Mark Purcell
  • Date: 2014-01-28 18:23:36 UTC
  • mfrom: (1.1.11)
  • mto: This revision was merged to the branch mainline in revision 24.
  • Revision ID: package-import@ubuntu.com-20140128182336-3xenud1kbnwmf3mz
* New upstream release 
  - Fixes "New Upstream Release" (Closes: #735846)
  - Fixes "Ringtone does not stop" (Closes: #727164)
  - Fixes "[sflphone-kde] crash on startup" (Closes: #718178)
  - Fixes "sflphone GUI crashes when call is hung up" (Closes: #736583)
* Build-Depends: ensure GnuTLS 2.6
  - libucommon-dev (>= 6.0.7-1.1), libccrtp-dev (>= 2.0.6-3)
  - Fixes "FTBFS Build-Depends libgnutls{26,28}-dev" (Closes: #722040)
* Fix "boost 1.49 is going away" unversioned Build-Depends: (Closes: #736746)
* Add Build-Depends: libsndfile-dev, nepomuk-core-dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: os_core_unix.c 4359 2013-02-21 11:18:36Z bennylp $ */
 
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
/*
 
21
 * Contributors:
 
22
 * - Thanks for Zetron, Inc. (Phil Torre, ptorre@zetron.com) for donating
 
23
 *   the RTEMS port.
 
24
 */
 
25
#ifndef _GNU_SOURCE
 
26
#   define _GNU_SOURCE
 
27
#endif
 
28
#include <pj/os.h>
 
29
#include <pj/assert.h>
 
30
#include <pj/pool.h>
 
31
#include <pj/log.h>
 
32
#include <pj/rand.h>
 
33
#include <pj/string.h>
 
34
#include <pj/guid.h>
 
35
#include <pj/except.h>
 
36
#include <pj/errno.h>
 
37
 
 
38
#if defined(PJ_HAS_SEMAPHORE_H) && PJ_HAS_SEMAPHORE_H != 0
 
39
#  include <semaphore.h>
 
40
#endif
 
41
 
 
42
#include <unistd.h>         // getpid()
 
43
#include <errno.h>          // errno
 
44
 
 
45
#include <pthread.h>
 
46
 
 
47
#define THIS_FILE   "os_core_unix.c"
 
48
 
 
49
#define SIGNATURE1  0xDEAFBEEF
 
50
#define SIGNATURE2  0xDEADC0DE
 
51
 
 
52
struct pj_thread_t
 
53
{
 
54
    char            obj_name[PJ_MAX_OBJ_NAME];
 
55
    pthread_t       thread;
 
56
    pj_thread_proc *proc;
 
57
    void           *arg;
 
58
    pj_uint32_t     signature1;
 
59
    pj_uint32_t     signature2;
 
60
 
 
61
    pj_mutex_t     *suspended_mutex;
 
62
 
 
63
#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
 
64
    pj_uint32_t     stk_size;
 
65
    pj_uint32_t     stk_max_usage;
 
66
    char           *stk_start;
 
67
    const char     *caller_file;
 
68
    int             caller_line;
 
69
#endif
 
70
};
 
71
 
 
72
struct pj_atomic_t
 
73
{
 
74
    pj_mutex_t         *mutex;
 
75
    pj_atomic_value_t   value;
 
76
};
 
77
 
 
78
struct pj_mutex_t
 
79
{
 
80
    pthread_mutex_t     mutex;
 
81
    char                obj_name[PJ_MAX_OBJ_NAME];
 
82
#if PJ_DEBUG
 
83
    int                 nesting_level;
 
84
    pj_thread_t        *owner;
 
85
    char                owner_name[PJ_MAX_OBJ_NAME];
 
86
#endif
 
87
};
 
88
 
 
89
#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0
 
90
struct pj_sem_t
 
91
{
 
92
    sem_t              *sem;
 
93
    char                obj_name[PJ_MAX_OBJ_NAME];
 
94
};
 
95
#endif /* PJ_HAS_SEMAPHORE */
 
96
 
 
97
#if defined(PJ_HAS_EVENT_OBJ) && PJ_HAS_EVENT_OBJ != 0
 
98
struct pj_event_t
 
99
{
 
100
    enum event_state {
 
101
        EV_STATE_OFF,
 
102
        EV_STATE_SET,
 
103
        EV_STATE_PULSED
 
104
    } state;
 
105
 
 
106
    pj_mutex_t          mutex;
 
107
    pthread_cond_t      cond;
 
108
 
 
109
    pj_bool_t           auto_reset;
 
110
    unsigned            threads_waiting;
 
111
    unsigned            threads_to_release;
 
112
};
 
113
#endif  /* PJ_HAS_EVENT_OBJ */
 
114
 
 
115
 
 
116
/*
 
117
 * Flag and reference counter for PJLIB instance.
 
118
 */
 
119
static int initialized;
 
120
 
 
121
#if PJ_HAS_THREADS
 
122
    static pj_thread_t main_thread;
 
123
    static long thread_tls_id;
 
124
    static pj_mutex_t critical_section;
 
125
#else
 
126
#   define MAX_THREADS 32
 
127
    static int tls_flag[MAX_THREADS];
 
128
    static void *tls[MAX_THREADS];
 
129
#endif
 
130
 
 
131
static unsigned atexit_count;
 
132
static void (*atexit_func[32])(void);
 
133
 
 
134
static pj_status_t init_mutex(pj_mutex_t *mutex, const char *name, int type);
 
135
 
 
136
/*
 
137
 * pj_init(void).
 
138
 * Init PJLIB!
 
139
 */
 
140
PJ_DEF(pj_status_t) pj_init(void)
 
141
{
 
142
    char dummy_guid[PJ_GUID_MAX_LENGTH];
 
143
    pj_str_t guid;
 
144
    pj_status_t rc;
 
145
 
 
146
    /* Check if PJLIB have been initialized */
 
147
    if (initialized) {
 
148
        ++initialized;
 
149
        return PJ_SUCCESS;
 
150
    }
 
151
 
 
152
#if PJ_HAS_THREADS
 
153
    /* Init this thread's TLS. */
 
154
    if ((rc=pj_thread_init()) != 0) {
 
155
        return rc;
 
156
    }
 
157
 
 
158
    /* Critical section. */
 
159
    if ((rc=init_mutex(&critical_section, "critsec", PJ_MUTEX_RECURSE)) != 0)
 
160
        return rc;
 
161
 
 
162
#endif
 
163
 
 
164
    /* Init logging */
 
165
    pj_log_init();
 
166
 
 
167
    /* Initialize exception ID for the pool. 
 
168
     * Must do so after critical section is configured.
 
169
     */
 
170
    rc = pj_exception_id_alloc("PJLIB/No memory", &PJ_NO_MEMORY_EXCEPTION);
 
171
    if (rc != PJ_SUCCESS)
 
172
        return rc;
 
173
    
 
174
    /* Init random seed. */
 
175
    /* Or probably not. Let application in charge of this */
 
176
    /* pj_srand( clock() ); */
 
177
 
 
178
    /* Startup GUID. */
 
179
    guid.ptr = dummy_guid;
 
180
    pj_generate_unique_string( &guid );
 
181
 
 
182
    /* Startup timestamp */
 
183
#if defined(PJ_HAS_HIGH_RES_TIMER) && PJ_HAS_HIGH_RES_TIMER != 0
 
184
    {
 
185
        pj_timestamp dummy_ts;
 
186
        if ((rc=pj_get_timestamp(&dummy_ts)) != 0) {
 
187
            return rc;
 
188
        }
 
189
    }
 
190
#endif   
 
191
 
 
192
    /* Flag PJLIB as initialized */
 
193
    ++initialized;
 
194
    pj_assert(initialized == 1);
 
195
 
 
196
    PJ_LOG(4,(THIS_FILE, "pjlib %s for POSIX initialized",
 
197
              PJ_VERSION));
 
198
 
 
199
    return PJ_SUCCESS;
 
200
}
 
201
 
 
202
/*
 
203
 * pj_atexit()
 
204
 */
 
205
PJ_DEF(pj_status_t) pj_atexit(void (*func)(void))
 
206
{
 
207
    if (atexit_count >= PJ_ARRAY_SIZE(atexit_func))
 
208
        return PJ_ETOOMANY;
 
209
 
 
210
    atexit_func[atexit_count++] = func;
 
211
    return PJ_SUCCESS;
 
212
}
 
213
 
 
214
/*
 
215
 * pj_shutdown(void)
 
216
 */
 
217
PJ_DEF(void) pj_shutdown()
 
218
{
 
219
    int i;
 
220
 
 
221
    /* Only perform shutdown operation when 'initialized' reaches zero */
 
222
    pj_assert(initialized > 0);
 
223
    if (--initialized != 0)
 
224
        return;
 
225
 
 
226
    /* Call atexit() functions */
 
227
    for (i=atexit_count-1; i>=0; --i) {
 
228
        (*atexit_func[i])();
 
229
    }
 
230
    atexit_count = 0;
 
231
 
 
232
    /* Free exception ID */
 
233
    if (PJ_NO_MEMORY_EXCEPTION != -1) {
 
234
        pj_exception_id_free(PJ_NO_MEMORY_EXCEPTION);
 
235
        PJ_NO_MEMORY_EXCEPTION = -1;
 
236
    }
 
237
 
 
238
#if PJ_HAS_THREADS
 
239
    /* Destroy PJLIB critical section */
 
240
    pj_mutex_destroy(&critical_section);
 
241
 
 
242
    /* Free PJLIB TLS */
 
243
    if (thread_tls_id != -1) {
 
244
        pj_thread_local_free(thread_tls_id);
 
245
        thread_tls_id = -1;
 
246
    }
 
247
 
 
248
    /* Ticket #1132: Assertion when (re)starting PJLIB on different thread */
 
249
    pj_bzero(&main_thread, sizeof(main_thread));
 
250
#endif
 
251
 
 
252
    /* Clear static variables */
 
253
    pj_errno_clear_handlers();
 
254
}
 
255
 
 
256
 
 
257
/*
 
258
 * pj_getpid(void)
 
259
 */
 
260
PJ_DEF(pj_uint32_t) pj_getpid(void)
 
261
{
 
262
    PJ_CHECK_STACK();
 
263
    return getpid();
 
264
}
 
265
 
 
266
/*
 
267
 * Check if this thread has been registered to PJLIB.
 
268
 */
 
269
PJ_DEF(pj_bool_t) pj_thread_is_registered(void)
 
270
{
 
271
#if PJ_HAS_THREADS
 
272
    return pj_thread_local_get(thread_tls_id) != 0;
 
273
#else
 
274
    pj_assert("pj_thread_is_registered() called in non-threading mode!");
 
275
    return PJ_TRUE;
 
276
#endif
 
277
}
 
278
 
 
279
 
 
280
/*
 
281
 * Get thread priority value for the thread.
 
282
 */
 
283
PJ_DEF(int) pj_thread_get_prio(pj_thread_t *thread)
 
284
{
 
285
#if PJ_HAS_THREADS
 
286
    struct sched_param param;
 
287
    int policy;
 
288
    int rc;
 
289
 
 
290
    rc = pthread_getschedparam (thread->thread, &policy, &param);
 
291
    if (rc != 0)
 
292
        return -1;
 
293
 
 
294
    return param.sched_priority;
 
295
#else
 
296
    PJ_UNUSED_ARG(thread);
 
297
    return 1;
 
298
#endif
 
299
}
 
300
 
 
301
 
 
302
/*
 
303
 * Set the thread priority.
 
304
 */
 
305
PJ_DEF(pj_status_t) pj_thread_set_prio(pj_thread_t *thread,  int prio)
 
306
{
 
307
#if PJ_HAS_THREADS
 
308
    struct sched_param param;
 
309
    int policy;
 
310
    int rc;
 
311
 
 
312
    rc = pthread_getschedparam (thread->thread, &policy, &param);
 
313
    if (rc != 0)
 
314
        return PJ_RETURN_OS_ERROR(rc);
 
315
 
 
316
    param.sched_priority = prio;
 
317
 
 
318
    rc = pthread_setschedparam(thread->thread, policy, &param);
 
319
    if (rc != 0)
 
320
        return PJ_RETURN_OS_ERROR(rc);
 
321
 
 
322
    return PJ_SUCCESS;
 
323
#else
 
324
    PJ_UNUSED_ARG(thread);
 
325
    PJ_UNUSED_ARG(prio);
 
326
    pj_assert("pj_thread_set_prio() called in non-threading mode!");
 
327
    return 1;
 
328
#endif
 
329
}
 
330
 
 
331
 
 
332
/*
 
333
 * Get the lowest priority value available on this system.
 
334
 */
 
335
PJ_DEF(int) pj_thread_get_prio_min(pj_thread_t *thread)
 
336
{
 
337
    struct sched_param param;
 
338
    int policy;
 
339
    int rc;
 
340
 
 
341
    rc = pthread_getschedparam(thread->thread, &policy, &param);
 
342
    if (rc != 0)
 
343
        return -1;
 
344
 
 
345
#if defined(_POSIX_PRIORITY_SCHEDULING)
 
346
    return sched_get_priority_min(policy);
 
347
#elif defined __OpenBSD__
 
348
    /* Thread prio min/max are declared in OpenBSD private hdr */
 
349
    return 0;
 
350
#else
 
351
    pj_assert("pj_thread_get_prio_min() not supported!");
 
352
    return 0;
 
353
#endif
 
354
}
 
355
 
 
356
 
 
357
/*
 
358
 * Get the highest priority value available on this system.
 
359
 */
 
360
PJ_DEF(int) pj_thread_get_prio_max(pj_thread_t *thread)
 
361
{
 
362
    struct sched_param param;
 
363
    int policy;
 
364
    int rc;
 
365
 
 
366
    rc = pthread_getschedparam(thread->thread, &policy, &param);
 
367
    if (rc != 0)
 
368
        return -1;
 
369
 
 
370
#if defined(_POSIX_PRIORITY_SCHEDULING)
 
371
    return sched_get_priority_max(policy);
 
372
#elif defined __OpenBSD__
 
373
    /* Thread prio min/max are declared in OpenBSD private hdr */
 
374
    return 31;
 
375
#else
 
376
    pj_assert("pj_thread_get_prio_max() not supported!");
 
377
    return 0;
 
378
#endif
 
379
}
 
380
 
 
381
 
 
382
/*
 
383
 * Get native thread handle
 
384
 */
 
385
PJ_DEF(void*) pj_thread_get_os_handle(pj_thread_t *thread) 
 
386
{
 
387
    PJ_ASSERT_RETURN(thread, NULL);
 
388
 
 
389
#if PJ_HAS_THREADS
 
390
    return &thread->thread;
 
391
#else
 
392
    pj_assert("pj_thread_is_registered() called in non-threading mode!");
 
393
    return NULL;
 
394
#endif
 
395
}
 
396
 
 
397
/*
 
398
 * pj_thread_register(..)
 
399
 */
 
400
PJ_DEF(pj_status_t) pj_thread_register ( const char *cstr_thread_name,
 
401
                                         pj_thread_desc desc,
 
402
                                         pj_thread_t **ptr_thread)
 
403
{
 
404
#if PJ_HAS_THREADS
 
405
    char stack_ptr;
 
406
    pj_status_t rc;
 
407
    pj_thread_t *thread = (pj_thread_t *)desc;
 
408
    pj_str_t thread_name = pj_str((char*)cstr_thread_name);
 
409
 
 
410
    /* Size sanity check. */
 
411
    if (sizeof(pj_thread_desc) < sizeof(pj_thread_t)) {
 
412
        pj_assert(!"Not enough pj_thread_desc size!");
 
413
        return PJ_EBUG;
 
414
    }
 
415
 
 
416
    /* Warn if this thread has been registered before */
 
417
    if (pj_thread_local_get (thread_tls_id) != 0) {
 
418
        // 2006-02-26 bennylp:
 
419
        //  This wouldn't work in all cases!.
 
420
        //  If thread is created by external module (e.g. sound thread),
 
421
        //  thread may be reused while the pool used for the thread descriptor
 
422
        //  has been deleted by application.
 
423
        //*thread_ptr = (pj_thread_t*)pj_thread_local_get (thread_tls_id);
 
424
        //return PJ_SUCCESS;
 
425
        PJ_LOG(4,(THIS_FILE, "Info: possibly re-registering existing "
 
426
                             "thread"));
 
427
    }
 
428
 
 
429
    /* On the other hand, also warn if the thread descriptor buffer seem to
 
430
     * have been used to register other threads.
 
431
     */
 
432
    pj_assert(thread->signature1 != SIGNATURE1 ||
 
433
              thread->signature2 != SIGNATURE2 ||
 
434
              (thread->thread == pthread_self()));
 
435
 
 
436
    /* Initialize and set the thread entry. */
 
437
    pj_bzero(desc, sizeof(struct pj_thread_t));
 
438
    thread->thread = pthread_self();
 
439
    thread->signature1 = SIGNATURE1;
 
440
    thread->signature2 = SIGNATURE2;
 
441
 
 
442
    if(cstr_thread_name && pj_strlen(&thread_name) < sizeof(thread->obj_name)-1)
 
443
        pj_ansi_snprintf(thread->obj_name, sizeof(thread->obj_name), 
 
444
                         cstr_thread_name, thread->thread);
 
445
    else
 
446
        pj_ansi_snprintf(thread->obj_name, sizeof(thread->obj_name), 
 
447
                         "thr%p", (void*)thread->thread);
 
448
    
 
449
    rc = pj_thread_local_set(thread_tls_id, thread);
 
450
    if (rc != PJ_SUCCESS) {
 
451
        pj_bzero(desc, sizeof(struct pj_thread_t));
 
452
        return rc;
 
453
    }
 
454
 
 
455
#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
 
456
    thread->stk_start = &stack_ptr;
 
457
    thread->stk_size = 0xFFFFFFFFUL;
 
458
    thread->stk_max_usage = 0;
 
459
#else
 
460
    stack_ptr = '\0';
 
461
#endif
 
462
 
 
463
    *ptr_thread = thread;
 
464
    return PJ_SUCCESS;
 
465
#else
 
466
    pj_thread_t *thread = (pj_thread_t*)desc;
 
467
    *ptr_thread = thread;
 
468
    return PJ_SUCCESS;
 
469
#endif
 
470
}
 
471
 
 
472
/*
 
473
 * pj_thread_init(void)
 
474
 */
 
475
pj_status_t pj_thread_init(void)
 
476
{
 
477
#if PJ_HAS_THREADS
 
478
    pj_status_t rc;
 
479
    pj_thread_t *dummy;
 
480
 
 
481
    rc = pj_thread_local_alloc(&thread_tls_id );
 
482
    if (rc != PJ_SUCCESS) {
 
483
        return rc;
 
484
    }
 
485
    return pj_thread_register("thr%p", (long*)&main_thread, &dummy);
 
486
#else
 
487
    PJ_LOG(2,(THIS_FILE, "Thread init error. Threading is not enabled!"));
 
488
    return PJ_EINVALIDOP;
 
489
#endif
 
490
}
 
491
 
 
492
#if PJ_HAS_THREADS
 
493
/*
 
494
 * thread_main()
 
495
 *
 
496
 * This is the main entry for all threads.
 
497
 */
 
498
static void *thread_main(void *param)
 
499
{
 
500
    pj_thread_t *rec = (pj_thread_t*)param;
 
501
    void *result;
 
502
    pj_status_t rc;
 
503
 
 
504
#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
 
505
    rec->stk_start = (char*)&rec;
 
506
#endif
 
507
 
 
508
    /* Set current thread id. */
 
509
    rc = pj_thread_local_set(thread_tls_id, rec);
 
510
    if (rc != PJ_SUCCESS) {
 
511
        pj_assert(!"Thread TLS ID is not set (pj_init() error?)");
 
512
    }
 
513
 
 
514
    /* Check if suspension is required. */
 
515
    if (rec->suspended_mutex) {
 
516
        pj_mutex_lock(rec->suspended_mutex);
 
517
        pj_mutex_unlock(rec->suspended_mutex);
 
518
    }
 
519
 
 
520
    PJ_LOG(6,(rec->obj_name, "Thread started"));
 
521
 
 
522
    /* Call user's entry! */
 
523
    result = (void*)(long)(*rec->proc)(rec->arg);
 
524
 
 
525
    /* Done. */
 
526
    PJ_LOG(6,(rec->obj_name, "Thread quitting"));
 
527
 
 
528
    return result;
 
529
}
 
530
#endif
 
531
 
 
532
/*
 
533
 * pj_thread_create(...)
 
534
 */
 
535
PJ_DEF(pj_status_t) pj_thread_create( pj_pool_t *pool, 
 
536
                                      const char *thread_name,
 
537
                                      pj_thread_proc *proc, 
 
538
                                      void *arg,
 
539
                                      pj_size_t stack_size, 
 
540
                                      unsigned flags,
 
541
                                      pj_thread_t **ptr_thread)
 
542
{
 
543
#if PJ_HAS_THREADS
 
544
    pj_thread_t *rec;
 
545
    pthread_attr_t thread_attr;
 
546
    void *stack_addr;
 
547
    int rc;
 
548
 
 
549
    PJ_UNUSED_ARG(stack_addr);
 
550
 
 
551
    PJ_CHECK_STACK();
 
552
    PJ_ASSERT_RETURN(pool && proc && ptr_thread, PJ_EINVAL);
 
553
 
 
554
    /* Create thread record and assign name for the thread */
 
555
    rec = (struct pj_thread_t*) pj_pool_zalloc(pool, sizeof(pj_thread_t));
 
556
    PJ_ASSERT_RETURN(rec, PJ_ENOMEM);
 
557
    
 
558
    /* Set name. */
 
559
    if (!thread_name) 
 
560
        thread_name = "thr%p";
 
561
    
 
562
    if (strchr(thread_name, '%')) {
 
563
        pj_ansi_snprintf(rec->obj_name, PJ_MAX_OBJ_NAME, thread_name, rec);
 
564
    } else {
 
565
        strncpy(rec->obj_name, thread_name, PJ_MAX_OBJ_NAME);
 
566
        rec->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
 
567
    }
 
568
 
 
569
    /* Set default stack size */
 
570
    if (stack_size == 0)
 
571
        stack_size = PJ_THREAD_DEFAULT_STACK_SIZE;
 
572
 
 
573
#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
 
574
    rec->stk_size = stack_size;
 
575
    rec->stk_max_usage = 0;
 
576
#endif
 
577
 
 
578
    /* Emulate suspended thread with mutex. */
 
579
    if (flags & PJ_THREAD_SUSPENDED) {
 
580
        rc = pj_mutex_create_simple(pool, NULL, &rec->suspended_mutex);
 
581
        if (rc != PJ_SUCCESS) {
 
582
            return rc;
 
583
        }
 
584
 
 
585
        pj_mutex_lock(rec->suspended_mutex);
 
586
    } else {
 
587
        pj_assert(rec->suspended_mutex == NULL);
 
588
    }
 
589
    
 
590
 
 
591
    /* Init thread attributes */
 
592
    pthread_attr_init(&thread_attr);
 
593
 
 
594
#if defined(PJ_THREAD_SET_STACK_SIZE) && PJ_THREAD_SET_STACK_SIZE!=0
 
595
    /* Set thread's stack size */
 
596
    rc = pthread_attr_setstacksize(&thread_attr, stack_size);
 
597
    if (rc != 0)
 
598
        return PJ_RETURN_OS_ERROR(rc);
 
599
#endif  /* PJ_THREAD_SET_STACK_SIZE */
 
600
 
 
601
 
 
602
#if defined(PJ_THREAD_ALLOCATE_STACK) && PJ_THREAD_ALLOCATE_STACK!=0
 
603
    /* Allocate memory for the stack */
 
604
    stack_addr = pj_pool_alloc(pool, stack_size);
 
605
    PJ_ASSERT_RETURN(stack_addr, PJ_ENOMEM);
 
606
 
 
607
    rc = pthread_attr_setstackaddr(&thread_attr, stack_addr);
 
608
    if (rc != 0)
 
609
        return PJ_RETURN_OS_ERROR(rc);
 
610
#endif  /* PJ_THREAD_ALLOCATE_STACK */
 
611
 
 
612
 
 
613
    /* Create the thread. */
 
614
    rec->proc = proc;
 
615
    rec->arg = arg;
 
616
    rc = pthread_create( &rec->thread, &thread_attr, &thread_main, rec);
 
617
    if (rc != 0) {
 
618
        return PJ_RETURN_OS_ERROR(rc);
 
619
    }
 
620
 
 
621
    *ptr_thread = rec;
 
622
 
 
623
    PJ_LOG(6, (rec->obj_name, "Thread created"));
 
624
    return PJ_SUCCESS;
 
625
#else
 
626
    pj_assert(!"Threading is disabled!");
 
627
    return PJ_EINVALIDOP;
 
628
#endif
 
629
}
 
630
 
 
631
/*
 
632
 * pj_thread-get_name()
 
633
 */
 
634
PJ_DEF(const char*) pj_thread_get_name(pj_thread_t *p)
 
635
{
 
636
#if PJ_HAS_THREADS
 
637
    pj_thread_t *rec = (pj_thread_t*)p;
 
638
 
 
639
    PJ_CHECK_STACK();
 
640
    PJ_ASSERT_RETURN(p, "");
 
641
 
 
642
    return rec->obj_name;
 
643
#else
 
644
    return "";
 
645
#endif
 
646
}
 
647
 
 
648
/*
 
649
 * pj_thread_resume()
 
650
 */
 
651
PJ_DEF(pj_status_t) pj_thread_resume(pj_thread_t *p)
 
652
{
 
653
    pj_status_t rc;
 
654
 
 
655
    PJ_CHECK_STACK();
 
656
    PJ_ASSERT_RETURN(p, PJ_EINVAL);
 
657
 
 
658
    rc = pj_mutex_unlock(p->suspended_mutex);
 
659
 
 
660
    return rc;
 
661
}
 
662
 
 
663
/*
 
664
 * pj_thread_this()
 
665
 */
 
666
PJ_DEF(pj_thread_t*) pj_thread_this(void)
 
667
{
 
668
#if PJ_HAS_THREADS
 
669
    pj_thread_t *rec = (pj_thread_t*)pj_thread_local_get(thread_tls_id);
 
670
    
 
671
    if (rec == NULL) {
 
672
        pj_assert(!"Calling pjlib from unknown/external thread. You must "
 
673
                   "register external threads with pj_thread_register() "
 
674
                   "before calling any pjlib functions.");
 
675
    }
 
676
 
 
677
    /*
 
678
     * MUST NOT check stack because this function is called
 
679
     * by PJ_CHECK_STACK() itself!!!
 
680
     *
 
681
     */
 
682
 
 
683
    return rec;
 
684
#else
 
685
    pj_assert(!"Threading is not enabled!");
 
686
    return NULL;
 
687
#endif
 
688
}
 
689
 
 
690
/*
 
691
 * pj_thread_join()
 
692
 */
 
693
PJ_DEF(pj_status_t) pj_thread_join(pj_thread_t *p)
 
694
{
 
695
#if PJ_HAS_THREADS
 
696
    pj_thread_t *rec = (pj_thread_t *)p;
 
697
    void *ret;
 
698
    int result;
 
699
 
 
700
    PJ_CHECK_STACK();
 
701
 
 
702
    PJ_LOG(6, (pj_thread_this()->obj_name, "Joining thread %s", p->obj_name));
 
703
    result = pthread_join( rec->thread, &ret);
 
704
 
 
705
    if (result == 0)
 
706
        return PJ_SUCCESS;
 
707
    else {
 
708
        /* Calling pthread_join() on a thread that no longer exists and 
 
709
         * getting back ESRCH isn't an error (in this context). 
 
710
         * Thanks Phil Torre <ptorre@zetron.com>.
 
711
         */
 
712
        return result==ESRCH ? PJ_SUCCESS : PJ_RETURN_OS_ERROR(result);
 
713
    }
 
714
#else
 
715
    PJ_CHECK_STACK();
 
716
    pj_assert(!"No multithreading support!");
 
717
    return PJ_EINVALIDOP;
 
718
#endif
 
719
}
 
720
 
 
721
/*
 
722
 * pj_thread_destroy()
 
723
 */
 
724
PJ_DEF(pj_status_t) pj_thread_destroy(pj_thread_t *p)
 
725
{
 
726
    PJ_CHECK_STACK();
 
727
 
 
728
    /* Destroy mutex used to suspend thread */
 
729
    if (p->suspended_mutex) {
 
730
        pj_mutex_destroy(p->suspended_mutex);
 
731
        p->suspended_mutex = NULL;
 
732
    }
 
733
 
 
734
    return PJ_SUCCESS;
 
735
}
 
736
 
 
737
/*
 
738
 * pj_thread_sleep()
 
739
 */
 
740
PJ_DEF(pj_status_t) pj_thread_sleep(unsigned msec)
 
741
{
 
742
/* TODO: should change this to something like PJ_OS_HAS_NANOSLEEP */
 
743
#if defined(PJ_RTEMS) && PJ_RTEMS!=0
 
744
    enum { NANOSEC_PER_MSEC = 1000000 };
 
745
    struct timespec req;
 
746
 
 
747
    PJ_CHECK_STACK();
 
748
    req.tv_sec = msec / 1000;
 
749
    req.tv_nsec = (msec % 1000) * NANOSEC_PER_MSEC;
 
750
 
 
751
    if (nanosleep(&req, NULL) == 0)
 
752
        return PJ_SUCCESS;
 
753
 
 
754
    return PJ_RETURN_OS_ERROR(pj_get_native_os_error());
 
755
#else
 
756
    PJ_CHECK_STACK();
 
757
 
 
758
    pj_set_os_error(0);
 
759
 
 
760
    usleep(msec * 1000);
 
761
 
 
762
    /* MacOS X (reported on 10.5) seems to always set errno to ETIMEDOUT.
 
763
     * It does so because usleep() is declared to return int, and we're
 
764
     * supposed to check for errno only when usleep() returns non-zero. 
 
765
     * Unfortunately, usleep() is declared to return void in other platforms
 
766
     * so it's not possible to always check for the return value (unless 
 
767
     * we add a detection routine in autoconf).
 
768
     *
 
769
     * As a workaround, here we check if ETIMEDOUT is returned and
 
770
     * return successfully if it is.
 
771
     */
 
772
    if (pj_get_native_os_error() == ETIMEDOUT)
 
773
        return PJ_SUCCESS;
 
774
 
 
775
    return pj_get_os_error();
 
776
 
 
777
#endif  /* PJ_RTEMS */
 
778
}
 
779
 
 
780
#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
 
781
/*
 
782
 * pj_thread_check_stack()
 
783
 * Implementation for PJ_CHECK_STACK()
 
784
 */
 
785
PJ_DEF(void) pj_thread_check_stack(const char *file, int line)
 
786
{
 
787
    char stk_ptr;
 
788
    pj_uint32_t usage;
 
789
    pj_thread_t *thread = pj_thread_this();
 
790
 
 
791
    /* Calculate current usage. */
 
792
    usage = (&stk_ptr > thread->stk_start) ? &stk_ptr - thread->stk_start :
 
793
                thread->stk_start - &stk_ptr;
 
794
 
 
795
    /* Assert if stack usage is dangerously high. */
 
796
    pj_assert("STACK OVERFLOW!! " && (usage <= thread->stk_size - 128));
 
797
 
 
798
    /* Keep statistic. */
 
799
    if (usage > thread->stk_max_usage) {
 
800
        thread->stk_max_usage = usage;
 
801
        thread->caller_file = file;
 
802
        thread->caller_line = line;
 
803
    }
 
804
}
 
805
 
 
806
/*
 
807
 * pj_thread_get_stack_max_usage()
 
808
 */
 
809
PJ_DEF(pj_uint32_t) pj_thread_get_stack_max_usage(pj_thread_t *thread)
 
810
{
 
811
    return thread->stk_max_usage;
 
812
}
 
813
 
 
814
/*
 
815
 * pj_thread_get_stack_info()
 
816
 */
 
817
PJ_DEF(pj_status_t) pj_thread_get_stack_info( pj_thread_t *thread,
 
818
                                              const char **file,
 
819
                                              int *line )
 
820
{
 
821
    pj_assert(thread);
 
822
 
 
823
    *file = thread->caller_file;
 
824
    *line = thread->caller_line;
 
825
    return 0;
 
826
}
 
827
 
 
828
#endif  /* PJ_OS_HAS_CHECK_STACK */
 
829
 
 
830
///////////////////////////////////////////////////////////////////////////////
 
831
/*
 
832
 * pj_atomic_create()
 
833
 */
 
834
PJ_DEF(pj_status_t) pj_atomic_create( pj_pool_t *pool, 
 
835
                                      pj_atomic_value_t initial,
 
836
                                      pj_atomic_t **ptr_atomic)
 
837
{
 
838
    pj_status_t rc;
 
839
    pj_atomic_t *atomic_var;
 
840
 
 
841
    atomic_var = PJ_POOL_ZALLOC_T(pool, pj_atomic_t);
 
842
 
 
843
    PJ_ASSERT_RETURN(atomic_var, PJ_ENOMEM);
 
844
    
 
845
#if PJ_HAS_THREADS
 
846
    rc = pj_mutex_create(pool, "atm%p", PJ_MUTEX_SIMPLE, &atomic_var->mutex);
 
847
    if (rc != PJ_SUCCESS)
 
848
        return rc;
 
849
#endif
 
850
    atomic_var->value = initial;
 
851
 
 
852
    *ptr_atomic = atomic_var;
 
853
    return PJ_SUCCESS;
 
854
}
 
855
 
 
856
/*
 
857
 * pj_atomic_destroy()
 
858
 */
 
859
PJ_DEF(pj_status_t) pj_atomic_destroy( pj_atomic_t *atomic_var )
 
860
{
 
861
    PJ_ASSERT_RETURN(atomic_var, PJ_EINVAL);
 
862
#if PJ_HAS_THREADS
 
863
    return pj_mutex_destroy( atomic_var->mutex );
 
864
#else
 
865
    return 0;
 
866
#endif
 
867
}
 
868
 
 
869
/*
 
870
 * pj_atomic_set()
 
871
 */
 
872
PJ_DEF(void) pj_atomic_set(pj_atomic_t *atomic_var, pj_atomic_value_t value)
 
873
{
 
874
    PJ_CHECK_STACK();
 
875
 
 
876
#if PJ_HAS_THREADS
 
877
    pj_mutex_lock( atomic_var->mutex );
 
878
#endif
 
879
    atomic_var->value = value;
 
880
#if PJ_HAS_THREADS
 
881
    pj_mutex_unlock( atomic_var->mutex);
 
882
#endif 
 
883
}
 
884
 
 
885
/*
 
886
 * pj_atomic_get()
 
887
 */
 
888
PJ_DEF(pj_atomic_value_t) pj_atomic_get(pj_atomic_t *atomic_var)
 
889
{
 
890
    pj_atomic_value_t oldval;
 
891
    
 
892
    PJ_CHECK_STACK();
 
893
 
 
894
#if PJ_HAS_THREADS
 
895
    pj_mutex_lock( atomic_var->mutex );
 
896
#endif
 
897
    oldval = atomic_var->value;
 
898
#if PJ_HAS_THREADS
 
899
    pj_mutex_unlock( atomic_var->mutex);
 
900
#endif
 
901
    return oldval;
 
902
}
 
903
 
 
904
/*
 
905
 * pj_atomic_inc_and_get()
 
906
 */
 
907
PJ_DEF(pj_atomic_value_t) pj_atomic_inc_and_get(pj_atomic_t *atomic_var)
 
908
{
 
909
    pj_atomic_value_t new_value;
 
910
 
 
911
    PJ_CHECK_STACK();
 
912
 
 
913
#if PJ_HAS_THREADS
 
914
    pj_mutex_lock( atomic_var->mutex );
 
915
#endif
 
916
    new_value = ++atomic_var->value;
 
917
#if PJ_HAS_THREADS
 
918
    pj_mutex_unlock( atomic_var->mutex);
 
919
#endif
 
920
 
 
921
    return new_value;
 
922
}
 
923
/*
 
924
 * pj_atomic_inc()
 
925
 */
 
926
PJ_DEF(void) pj_atomic_inc(pj_atomic_t *atomic_var)
 
927
{
 
928
    pj_atomic_inc_and_get(atomic_var);
 
929
}
 
930
 
 
931
/*
 
932
 * pj_atomic_dec_and_get()
 
933
 */
 
934
PJ_DEF(pj_atomic_value_t) pj_atomic_dec_and_get(pj_atomic_t *atomic_var)
 
935
{
 
936
    pj_atomic_value_t new_value;
 
937
 
 
938
    PJ_CHECK_STACK();
 
939
 
 
940
#if PJ_HAS_THREADS
 
941
    pj_mutex_lock( atomic_var->mutex );
 
942
#endif
 
943
    new_value = --atomic_var->value;
 
944
#if PJ_HAS_THREADS
 
945
    pj_mutex_unlock( atomic_var->mutex);
 
946
#endif
 
947
 
 
948
    return new_value;
 
949
}
 
950
 
 
951
/*
 
952
 * pj_atomic_dec()
 
953
 */
 
954
PJ_DEF(void) pj_atomic_dec(pj_atomic_t *atomic_var)
 
955
{
 
956
    pj_atomic_dec_and_get(atomic_var);
 
957
}
 
958
 
 
959
/*
 
960
 * pj_atomic_add_and_get()
 
961
 */ 
 
962
PJ_DEF(pj_atomic_value_t) pj_atomic_add_and_get( pj_atomic_t *atomic_var, 
 
963
                                                 pj_atomic_value_t value )
 
964
{
 
965
    pj_atomic_value_t new_value;
 
966
 
 
967
#if PJ_HAS_THREADS
 
968
    pj_mutex_lock(atomic_var->mutex);
 
969
#endif
 
970
    
 
971
    atomic_var->value += value;
 
972
    new_value = atomic_var->value;
 
973
 
 
974
#if PJ_HAS_THREADS
 
975
    pj_mutex_unlock(atomic_var->mutex);
 
976
#endif
 
977
 
 
978
    return new_value;
 
979
}
 
980
 
 
981
/*
 
982
 * pj_atomic_add()
 
983
 */ 
 
984
PJ_DEF(void) pj_atomic_add( pj_atomic_t *atomic_var, 
 
985
                            pj_atomic_value_t value )
 
986
{
 
987
    pj_atomic_add_and_get(atomic_var, value);
 
988
}
 
989
 
 
990
///////////////////////////////////////////////////////////////////////////////
 
991
/*
 
992
 * pj_thread_local_alloc()
 
993
 */
 
994
PJ_DEF(pj_status_t) pj_thread_local_alloc(long *p_index)
 
995
{
 
996
#if PJ_HAS_THREADS
 
997
    pthread_key_t key;
 
998
    int rc;
 
999
 
 
1000
    PJ_ASSERT_RETURN(p_index != NULL, PJ_EINVAL);
 
1001
 
 
1002
    pj_assert( sizeof(pthread_key_t) <= sizeof(long));
 
1003
    if ((rc=pthread_key_create(&key, NULL)) != 0)
 
1004
        return PJ_RETURN_OS_ERROR(rc);
 
1005
 
 
1006
    *p_index = key;
 
1007
    return PJ_SUCCESS;
 
1008
#else
 
1009
    int i;
 
1010
    for (i=0; i<MAX_THREADS; ++i) {
 
1011
        if (tls_flag[i] == 0)
 
1012
            break;
 
1013
    }
 
1014
    if (i == MAX_THREADS) 
 
1015
        return PJ_ETOOMANY;
 
1016
    
 
1017
    tls_flag[i] = 1;
 
1018
    tls[i] = NULL;
 
1019
 
 
1020
    *p_index = i;
 
1021
    return PJ_SUCCESS;
 
1022
#endif
 
1023
}
 
1024
 
 
1025
/*
 
1026
 * pj_thread_local_free()
 
1027
 */
 
1028
PJ_DEF(void) pj_thread_local_free(long index)
 
1029
{
 
1030
    PJ_CHECK_STACK();
 
1031
#if PJ_HAS_THREADS
 
1032
    pthread_key_delete(index);
 
1033
#else
 
1034
    tls_flag[index] = 0;
 
1035
#endif
 
1036
}
 
1037
 
 
1038
/*
 
1039
 * pj_thread_local_set()
 
1040
 */
 
1041
PJ_DEF(pj_status_t) pj_thread_local_set(long index, void *value)
 
1042
{
 
1043
    //Can't check stack because this function is called in the
 
1044
    //beginning before main thread is initialized.
 
1045
    //PJ_CHECK_STACK();
 
1046
#if PJ_HAS_THREADS
 
1047
    int rc=pthread_setspecific(index, value);
 
1048
    return rc==0 ? PJ_SUCCESS : PJ_RETURN_OS_ERROR(rc);
 
1049
#else
 
1050
    pj_assert(index >= 0 && index < MAX_THREADS);
 
1051
    tls[index] = value;
 
1052
    return PJ_SUCCESS;
 
1053
#endif
 
1054
}
 
1055
 
 
1056
PJ_DEF(void*) pj_thread_local_get(long index)
 
1057
{
 
1058
    //Can't check stack because this function is called
 
1059
    //by PJ_CHECK_STACK() itself!!!
 
1060
    //PJ_CHECK_STACK();
 
1061
#if PJ_HAS_THREADS
 
1062
    return pthread_getspecific(index);
 
1063
#else
 
1064
    pj_assert(index >= 0 && index < MAX_THREADS);
 
1065
    return tls[index];
 
1066
#endif
 
1067
}
 
1068
 
 
1069
///////////////////////////////////////////////////////////////////////////////
 
1070
PJ_DEF(void) pj_enter_critical_section(void)
 
1071
{
 
1072
#if PJ_HAS_THREADS
 
1073
    pj_mutex_lock(&critical_section);
 
1074
#endif
 
1075
}
 
1076
 
 
1077
PJ_DEF(void) pj_leave_critical_section(void)
 
1078
{
 
1079
#if PJ_HAS_THREADS
 
1080
    pj_mutex_unlock(&critical_section);
 
1081
#endif
 
1082
}
 
1083
 
 
1084
 
 
1085
///////////////////////////////////////////////////////////////////////////////
 
1086
#if defined(PJ_LINUX) && PJ_LINUX!=0
 
1087
PJ_BEGIN_DECL
 
1088
PJ_DECL(int) pthread_mutexattr_settype(pthread_mutexattr_t*,int);
 
1089
PJ_END_DECL
 
1090
#endif
 
1091
 
 
1092
static pj_status_t init_mutex(pj_mutex_t *mutex, const char *name, int type)
 
1093
{
 
1094
#if PJ_HAS_THREADS
 
1095
    pthread_mutexattr_t attr;
 
1096
    int rc;
 
1097
 
 
1098
    PJ_CHECK_STACK();
 
1099
 
 
1100
    rc = pthread_mutexattr_init(&attr);
 
1101
    if (rc != 0)
 
1102
        return PJ_RETURN_OS_ERROR(rc);
 
1103
 
 
1104
    if (type == PJ_MUTEX_SIMPLE) {
 
1105
#if (defined(PJ_LINUX) && PJ_LINUX!=0) || \
 
1106
    defined(PJ_HAS_PTHREAD_MUTEXATTR_SETTYPE)
 
1107
        rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_FAST_NP);
 
1108
#elif (defined(PJ_RTEMS) && PJ_RTEMS!=0) || \
 
1109
       defined(PJ_PTHREAD_MUTEXATTR_T_HAS_RECURSIVE)
 
1110
        /* Nothing to do, default is simple */
 
1111
#else
 
1112
        rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
 
1113
#endif
 
1114
    } else {
 
1115
#if (defined(PJ_LINUX) && PJ_LINUX!=0) || \
 
1116
     defined(PJ_HAS_PTHREAD_MUTEXATTR_SETTYPE)
 
1117
        rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP);
 
1118
#elif (defined(PJ_RTEMS) && PJ_RTEMS!=0) || \
 
1119
       defined(PJ_PTHREAD_MUTEXATTR_T_HAS_RECURSIVE)
 
1120
        // Phil Torre <ptorre@zetron.com>:
 
1121
        // The RTEMS implementation of POSIX mutexes doesn't include 
 
1122
        // pthread_mutexattr_settype(), so what follows is a hack
 
1123
        // until I get RTEMS patched to support the set/get functions.
 
1124
        //
 
1125
        // More info:
 
1126
        //   newlib's pthread also lacks pthread_mutexattr_settype(),
 
1127
        //   but it seems to have mutexattr.recursive.
 
1128
        PJ_TODO(FIX_RTEMS_RECURSIVE_MUTEX_TYPE)
 
1129
        attr.recursive = 1;
 
1130
#else
 
1131
        rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
 
1132
#endif
 
1133
    }
 
1134
    
 
1135
    if (rc != 0) {
 
1136
        return PJ_RETURN_OS_ERROR(rc);
 
1137
    }
 
1138
 
 
1139
    rc = pthread_mutex_init(&mutex->mutex, &attr);
 
1140
    if (rc != 0) {
 
1141
        return PJ_RETURN_OS_ERROR(rc);
 
1142
    }
 
1143
    
 
1144
    rc = pthread_mutexattr_destroy(&attr);
 
1145
    if (rc != 0) {
 
1146
        pj_status_t status = PJ_RETURN_OS_ERROR(rc);
 
1147
        pthread_mutex_destroy(&mutex->mutex);
 
1148
        return status;
 
1149
    }
 
1150
 
 
1151
#if PJ_DEBUG
 
1152
    /* Set owner. */
 
1153
    mutex->nesting_level = 0;
 
1154
    mutex->owner = NULL;
 
1155
#endif
 
1156
 
 
1157
    /* Set name. */
 
1158
    if (!name) {
 
1159
        name = "mtx%p";
 
1160
    }
 
1161
    if (strchr(name, '%')) {
 
1162
        pj_ansi_snprintf(mutex->obj_name, PJ_MAX_OBJ_NAME, name, mutex);
 
1163
    } else {
 
1164
        strncpy(mutex->obj_name, name, PJ_MAX_OBJ_NAME);
 
1165
        mutex->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
 
1166
    }
 
1167
 
 
1168
    PJ_LOG(6, (mutex->obj_name, "Mutex created"));
 
1169
    return PJ_SUCCESS;
 
1170
#else /* PJ_HAS_THREADS */
 
1171
    return PJ_SUCCESS;
 
1172
#endif
 
1173
}
 
1174
 
 
1175
/*
 
1176
 * pj_mutex_create()
 
1177
 */
 
1178
PJ_DEF(pj_status_t) pj_mutex_create(pj_pool_t *pool, 
 
1179
                                    const char *name, 
 
1180
                                    int type,
 
1181
                                    pj_mutex_t **ptr_mutex)
 
1182
{
 
1183
#if PJ_HAS_THREADS
 
1184
    pj_status_t rc;
 
1185
    pj_mutex_t *mutex;
 
1186
 
 
1187
    PJ_ASSERT_RETURN(pool && ptr_mutex, PJ_EINVAL);
 
1188
 
 
1189
    mutex = PJ_POOL_ALLOC_T(pool, pj_mutex_t);
 
1190
    PJ_ASSERT_RETURN(mutex, PJ_ENOMEM);
 
1191
 
 
1192
    if ((rc=init_mutex(mutex, name, type)) != PJ_SUCCESS)
 
1193
        return rc;
 
1194
    
 
1195
    *ptr_mutex = mutex;
 
1196
    return PJ_SUCCESS;
 
1197
#else /* PJ_HAS_THREADS */
 
1198
    *ptr_mutex = (pj_mutex_t*)1;
 
1199
    return PJ_SUCCESS;
 
1200
#endif
 
1201
}
 
1202
 
 
1203
/*
 
1204
 * pj_mutex_create_simple()
 
1205
 */
 
1206
PJ_DEF(pj_status_t) pj_mutex_create_simple( pj_pool_t *pool, 
 
1207
                                            const char *name,
 
1208
                                            pj_mutex_t **mutex )
 
1209
{
 
1210
    return pj_mutex_create(pool, name, PJ_MUTEX_SIMPLE, mutex);
 
1211
}
 
1212
 
 
1213
/*
 
1214
 * pj_mutex_create_recursive()
 
1215
 */
 
1216
PJ_DEF(pj_status_t) pj_mutex_create_recursive( pj_pool_t *pool,
 
1217
                                               const char *name,
 
1218
                                               pj_mutex_t **mutex )
 
1219
{
 
1220
    return pj_mutex_create(pool, name, PJ_MUTEX_RECURSE, mutex);
 
1221
}
 
1222
 
 
1223
/*
 
1224
 * pj_mutex_lock()
 
1225
 */
 
1226
PJ_DEF(pj_status_t) pj_mutex_lock(pj_mutex_t *mutex)
 
1227
{
 
1228
#if PJ_HAS_THREADS
 
1229
    pj_status_t status;
 
1230
 
 
1231
    PJ_CHECK_STACK();
 
1232
    PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
 
1233
 
 
1234
#if PJ_DEBUG
 
1235
    PJ_LOG(6,(mutex->obj_name, "Mutex: thread %s is waiting (mutex owner=%s)", 
 
1236
                                pj_thread_this()->obj_name,
 
1237
                                mutex->owner_name));
 
1238
#else
 
1239
    PJ_LOG(6,(mutex->obj_name, "Mutex: thread %s is waiting", 
 
1240
                                pj_thread_this()->obj_name));
 
1241
#endif
 
1242
 
 
1243
    status = pthread_mutex_lock( &mutex->mutex );
 
1244
 
 
1245
 
 
1246
#if PJ_DEBUG
 
1247
    if (status == PJ_SUCCESS) {
 
1248
        mutex->owner = pj_thread_this();
 
1249
        pj_ansi_strcpy(mutex->owner_name, mutex->owner->obj_name);
 
1250
        ++mutex->nesting_level;
 
1251
    }
 
1252
 
 
1253
    PJ_LOG(6,(mutex->obj_name, 
 
1254
              (status==0 ? 
 
1255
                "Mutex acquired by thread %s (level=%d)" : 
 
1256
                "Mutex acquisition FAILED by %s (level=%d)"),
 
1257
              pj_thread_this()->obj_name,
 
1258
              mutex->nesting_level));
 
1259
#else
 
1260
    PJ_LOG(6,(mutex->obj_name, 
 
1261
              (status==0 ? "Mutex acquired by thread %s" : "FAILED by %s"),
 
1262
              pj_thread_this()->obj_name));
 
1263
#endif
 
1264
 
 
1265
    if (status == 0)
 
1266
        return PJ_SUCCESS;
 
1267
    else
 
1268
        return PJ_RETURN_OS_ERROR(status);
 
1269
#else   /* PJ_HAS_THREADS */
 
1270
    pj_assert( mutex == (pj_mutex_t*)1 );
 
1271
    return PJ_SUCCESS;
 
1272
#endif
 
1273
}
 
1274
 
 
1275
/*
 
1276
 * pj_mutex_unlock()
 
1277
 */
 
1278
PJ_DEF(pj_status_t) pj_mutex_unlock(pj_mutex_t *mutex)
 
1279
{
 
1280
#if PJ_HAS_THREADS
 
1281
    pj_status_t status;
 
1282
 
 
1283
    PJ_CHECK_STACK();
 
1284
    PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
 
1285
 
 
1286
#if PJ_DEBUG
 
1287
    pj_assert(mutex->owner == pj_thread_this());
 
1288
    if (--mutex->nesting_level == 0) {
 
1289
        mutex->owner = NULL;
 
1290
        mutex->owner_name[0] = '\0';
 
1291
    }
 
1292
 
 
1293
    PJ_LOG(6,(mutex->obj_name, "Mutex released by thread %s (level=%d)", 
 
1294
                                pj_thread_this()->obj_name, 
 
1295
                                mutex->nesting_level));
 
1296
#else
 
1297
    PJ_LOG(6,(mutex->obj_name, "Mutex released by thread %s", 
 
1298
                                pj_thread_this()->obj_name));
 
1299
#endif
 
1300
 
 
1301
    status = pthread_mutex_unlock( &mutex->mutex );
 
1302
    if (status == 0)
 
1303
        return PJ_SUCCESS;
 
1304
    else
 
1305
        return PJ_RETURN_OS_ERROR(status);
 
1306
 
 
1307
#else /* PJ_HAS_THREADS */
 
1308
    pj_assert( mutex == (pj_mutex_t*)1 );
 
1309
    return PJ_SUCCESS;
 
1310
#endif
 
1311
}
 
1312
 
 
1313
/*
 
1314
 * pj_mutex_trylock()
 
1315
 */
 
1316
PJ_DEF(pj_status_t) pj_mutex_trylock(pj_mutex_t *mutex)
 
1317
{
 
1318
#if PJ_HAS_THREADS
 
1319
    int status;
 
1320
 
 
1321
    PJ_CHECK_STACK();
 
1322
    PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
 
1323
 
 
1324
    PJ_LOG(6,(mutex->obj_name, "Mutex: thread %s is trying", 
 
1325
                                pj_thread_this()->obj_name));
 
1326
 
 
1327
    status = pthread_mutex_trylock( &mutex->mutex );
 
1328
 
 
1329
    if (status==0) {
 
1330
#if PJ_DEBUG
 
1331
        mutex->owner = pj_thread_this();
 
1332
        pj_ansi_strcpy(mutex->owner_name, mutex->owner->obj_name);
 
1333
        ++mutex->nesting_level;
 
1334
 
 
1335
        PJ_LOG(6,(mutex->obj_name, "Mutex acquired by thread %s (level=%d)", 
 
1336
                                   pj_thread_this()->obj_name,
 
1337
                                   mutex->nesting_level));
 
1338
#else
 
1339
        PJ_LOG(6,(mutex->obj_name, "Mutex acquired by thread %s", 
 
1340
                                  pj_thread_this()->obj_name));
 
1341
#endif
 
1342
    } else {
 
1343
        PJ_LOG(6,(mutex->obj_name, "Mutex: thread %s's trylock() failed", 
 
1344
                                    pj_thread_this()->obj_name));
 
1345
    }
 
1346
    
 
1347
    if (status==0)
 
1348
        return PJ_SUCCESS;
 
1349
    else
 
1350
        return PJ_RETURN_OS_ERROR(status);
 
1351
#else   /* PJ_HAS_THREADS */
 
1352
    pj_assert( mutex == (pj_mutex_t*)1);
 
1353
    return PJ_SUCCESS;
 
1354
#endif
 
1355
}
 
1356
 
 
1357
/*
 
1358
 * pj_mutex_destroy()
 
1359
 */
 
1360
PJ_DEF(pj_status_t) pj_mutex_destroy(pj_mutex_t *mutex)
 
1361
{
 
1362
    enum { RETRY = 4 };
 
1363
    int status = 0;
 
1364
    unsigned retry;
 
1365
 
 
1366
    PJ_CHECK_STACK();
 
1367
    PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
 
1368
 
 
1369
#if PJ_HAS_THREADS
 
1370
    PJ_LOG(6,(mutex->obj_name, "Mutex destroyed by thread %s",
 
1371
                               pj_thread_this()->obj_name));
 
1372
 
 
1373
    for (retry=0; retry<RETRY; ++retry) {
 
1374
        status = pthread_mutex_destroy( &mutex->mutex );
 
1375
        if (status == PJ_SUCCESS)
 
1376
            break;
 
1377
        else if (retry<RETRY-1 && status == EBUSY)
 
1378
            pthread_mutex_unlock(&mutex->mutex);
 
1379
    }
 
1380
 
 
1381
    if (status == 0)
 
1382
        return PJ_SUCCESS;
 
1383
    else {
 
1384
        return PJ_RETURN_OS_ERROR(status);
 
1385
    }
 
1386
#else
 
1387
    pj_assert( mutex == (pj_mutex_t*)1 );
 
1388
    status = PJ_SUCCESS;
 
1389
    return status;
 
1390
#endif
 
1391
}
 
1392
 
 
1393
#if PJ_DEBUG
 
1394
PJ_DEF(pj_bool_t) pj_mutex_is_locked(pj_mutex_t *mutex)
 
1395
{
 
1396
#if PJ_HAS_THREADS
 
1397
    return mutex->owner == pj_thread_this();
 
1398
#else
 
1399
    return 1;
 
1400
#endif
 
1401
}
 
1402
#endif
 
1403
 
 
1404
///////////////////////////////////////////////////////////////////////////////
 
1405
/*
 
1406
 * Include Read/Write mutex emulation for POSIX platforms that lack it (e.g.
 
1407
 * RTEMS). Otherwise use POSIX rwlock.
 
1408
 */
 
1409
#if defined(PJ_EMULATE_RWMUTEX) && PJ_EMULATE_RWMUTEX!=0
 
1410
    /* We need semaphore functionality to emulate rwmutex */
 
1411
#   if !defined(PJ_HAS_SEMAPHORE) || PJ_HAS_SEMAPHORE==0
 
1412
#       error "Semaphore support needs to be enabled to emulate rwmutex"
 
1413
#   endif
 
1414
#   include "os_rwmutex.c"
 
1415
#else
 
1416
struct pj_rwmutex_t
 
1417
{
 
1418
    pthread_rwlock_t rwlock;
 
1419
};
 
1420
 
 
1421
PJ_DEF(pj_status_t) pj_rwmutex_create(pj_pool_t *pool, const char *name,
 
1422
                                      pj_rwmutex_t **p_mutex)
 
1423
{
 
1424
    pj_rwmutex_t *rwm;
 
1425
    pj_status_t status;
 
1426
 
 
1427
    PJ_UNUSED_ARG(name);
 
1428
    
 
1429
    rwm = PJ_POOL_ALLOC_T(pool, pj_rwmutex_t);
 
1430
    PJ_ASSERT_RETURN(rwm, PJ_ENOMEM);
 
1431
 
 
1432
    status = pthread_rwlock_init(&rwm->rwlock, NULL);
 
1433
    if (status != 0)
 
1434
        return PJ_RETURN_OS_ERROR(status);
 
1435
 
 
1436
    *p_mutex = rwm;
 
1437
    return PJ_SUCCESS;
 
1438
}
 
1439
 
 
1440
/*
 
1441
 * Lock the mutex for reading.
 
1442
 *
 
1443
 */
 
1444
PJ_DEF(pj_status_t) pj_rwmutex_lock_read(pj_rwmutex_t *mutex)
 
1445
{
 
1446
    pj_status_t status;
 
1447
 
 
1448
    status = pthread_rwlock_rdlock(&mutex->rwlock);
 
1449
    if (status != 0)
 
1450
        return PJ_RETURN_OS_ERROR(status);
 
1451
 
 
1452
    return PJ_SUCCESS;
 
1453
}
 
1454
 
 
1455
/*
 
1456
 * Lock the mutex for writing.
 
1457
 *
 
1458
 */
 
1459
PJ_DEF(pj_status_t) pj_rwmutex_lock_write(pj_rwmutex_t *mutex)
 
1460
{
 
1461
    pj_status_t status;
 
1462
 
 
1463
    status = pthread_rwlock_wrlock(&mutex->rwlock);
 
1464
    if (status != 0)
 
1465
        return PJ_RETURN_OS_ERROR(status);
 
1466
 
 
1467
    return PJ_SUCCESS;
 
1468
}
 
1469
 
 
1470
/*
 
1471
 * Release read lock.
 
1472
 *
 
1473
 */
 
1474
PJ_DEF(pj_status_t) pj_rwmutex_unlock_read(pj_rwmutex_t *mutex)
 
1475
{
 
1476
    return pj_rwmutex_unlock_write(mutex);
 
1477
}
 
1478
 
 
1479
/*
 
1480
 * Release write lock.
 
1481
 *
 
1482
 */
 
1483
PJ_DEF(pj_status_t) pj_rwmutex_unlock_write(pj_rwmutex_t *mutex)
 
1484
{
 
1485
    pj_status_t status;
 
1486
 
 
1487
    status = pthread_rwlock_unlock(&mutex->rwlock);
 
1488
    if (status != 0)
 
1489
        return PJ_RETURN_OS_ERROR(status);
 
1490
 
 
1491
    return PJ_SUCCESS;
 
1492
}
 
1493
 
 
1494
/*
 
1495
 * Destroy reader/writer mutex.
 
1496
 *
 
1497
 */
 
1498
PJ_DEF(pj_status_t) pj_rwmutex_destroy(pj_rwmutex_t *mutex)
 
1499
{
 
1500
    pj_status_t status;
 
1501
 
 
1502
    status = pthread_rwlock_destroy(&mutex->rwlock);
 
1503
    if (status != 0)
 
1504
        return PJ_RETURN_OS_ERROR(status);
 
1505
 
 
1506
    return PJ_SUCCESS;
 
1507
}
 
1508
 
 
1509
#endif  /* PJ_EMULATE_RWMUTEX */
 
1510
 
 
1511
 
 
1512
///////////////////////////////////////////////////////////////////////////////
 
1513
#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0
 
1514
 
 
1515
/*
 
1516
 * pj_sem_create()
 
1517
 */
 
1518
PJ_DEF(pj_status_t) pj_sem_create( pj_pool_t *pool, 
 
1519
                                   const char *name,
 
1520
                                   unsigned initial, 
 
1521
                                   unsigned max,
 
1522
                                   pj_sem_t **ptr_sem)
 
1523
{
 
1524
#if PJ_HAS_THREADS
 
1525
    pj_sem_t *sem;
 
1526
 
 
1527
    PJ_CHECK_STACK();
 
1528
    PJ_ASSERT_RETURN(pool != NULL && ptr_sem != NULL, PJ_EINVAL);
 
1529
 
 
1530
    sem = PJ_POOL_ALLOC_T(pool, pj_sem_t);
 
1531
    PJ_ASSERT_RETURN(sem, PJ_ENOMEM);
 
1532
 
 
1533
#if defined(PJ_DARWINOS) && PJ_DARWINOS!=0
 
1534
    /* MacOS X doesn't support anonymous semaphore */
 
1535
    {
 
1536
        char sem_name[PJ_GUID_MAX_LENGTH+1];
 
1537
        pj_str_t nam;
 
1538
 
 
1539
        /* We should use SEM_NAME_LEN, but this doesn't seem to be 
 
1540
         * declared anywhere? The value here is just from trial and error
 
1541
         * to get the longest name supported.
 
1542
         */
 
1543
#       define MAX_SEM_NAME_LEN 23
 
1544
 
 
1545
        /* Create a unique name for the semaphore. */
 
1546
        if (PJ_GUID_STRING_LENGTH <= MAX_SEM_NAME_LEN) {
 
1547
            nam.ptr = sem_name;
 
1548
            pj_generate_unique_string(&nam);
 
1549
            sem_name[nam.slen] = '\0';
 
1550
        } else {
 
1551
            pj_create_random_string(sem_name, MAX_SEM_NAME_LEN);
 
1552
            sem_name[MAX_SEM_NAME_LEN] = '\0';
 
1553
        }
 
1554
 
 
1555
        /* Create semaphore */
 
1556
        sem->sem = sem_open(sem_name, O_CREAT|O_EXCL, S_IRUSR|S_IWUSR, 
 
1557
                            initial);
 
1558
        if (sem->sem == SEM_FAILED)
 
1559
            return PJ_RETURN_OS_ERROR(pj_get_native_os_error());
 
1560
 
 
1561
        /* And immediately release the name as we don't need it */
 
1562
        sem_unlink(sem_name);
 
1563
    }
 
1564
#else
 
1565
    sem->sem = PJ_POOL_ALLOC_T(pool, sem_t);
 
1566
    if (sem_init( sem->sem, 0, initial) != 0) 
 
1567
        return PJ_RETURN_OS_ERROR(pj_get_native_os_error());
 
1568
#endif
 
1569
    
 
1570
    /* Set name. */
 
1571
    if (!name) {
 
1572
        name = "sem%p";
 
1573
    }
 
1574
    if (strchr(name, '%')) {
 
1575
        pj_ansi_snprintf(sem->obj_name, PJ_MAX_OBJ_NAME, name, sem);
 
1576
    } else {
 
1577
        strncpy(sem->obj_name, name, PJ_MAX_OBJ_NAME);
 
1578
        sem->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
 
1579
    }
 
1580
 
 
1581
    PJ_LOG(6, (sem->obj_name, "Semaphore created"));
 
1582
 
 
1583
    *ptr_sem = sem;
 
1584
    return PJ_SUCCESS;
 
1585
#else
 
1586
    *ptr_sem = (pj_sem_t*)1;
 
1587
    return PJ_SUCCESS;
 
1588
#endif
 
1589
}
 
1590
 
 
1591
/*
 
1592
 * pj_sem_wait()
 
1593
 */
 
1594
PJ_DEF(pj_status_t) pj_sem_wait(pj_sem_t *sem)
 
1595
{
 
1596
#if PJ_HAS_THREADS
 
1597
    int result;
 
1598
 
 
1599
    PJ_CHECK_STACK();
 
1600
    PJ_ASSERT_RETURN(sem, PJ_EINVAL);
 
1601
 
 
1602
    PJ_LOG(6, (sem->obj_name, "Semaphore: thread %s is waiting", 
 
1603
                              pj_thread_this()->obj_name));
 
1604
 
 
1605
    result = sem_wait( sem->sem );
 
1606
    
 
1607
    if (result == 0) {
 
1608
        PJ_LOG(6, (sem->obj_name, "Semaphore acquired by thread %s", 
 
1609
                                  pj_thread_this()->obj_name));
 
1610
    } else {
 
1611
        PJ_LOG(6, (sem->obj_name, "Semaphore: thread %s FAILED to acquire", 
 
1612
                                  pj_thread_this()->obj_name));
 
1613
    }
 
1614
 
 
1615
    if (result == 0)
 
1616
        return PJ_SUCCESS;
 
1617
    else
 
1618
        return PJ_RETURN_OS_ERROR(pj_get_native_os_error());
 
1619
#else
 
1620
    pj_assert( sem == (pj_sem_t*) 1 );
 
1621
    return PJ_SUCCESS;
 
1622
#endif
 
1623
}
 
1624
 
 
1625
/*
 
1626
 * pj_sem_trywait()
 
1627
 */
 
1628
PJ_DEF(pj_status_t) pj_sem_trywait(pj_sem_t *sem)
 
1629
{
 
1630
#if PJ_HAS_THREADS
 
1631
    int result;
 
1632
 
 
1633
    PJ_CHECK_STACK();
 
1634
    PJ_ASSERT_RETURN(sem, PJ_EINVAL);
 
1635
 
 
1636
    result = sem_trywait( sem->sem );
 
1637
    
 
1638
    if (result == 0) {
 
1639
        PJ_LOG(6, (sem->obj_name, "Semaphore acquired by thread %s", 
 
1640
                                  pj_thread_this()->obj_name));
 
1641
    } 
 
1642
    if (result == 0)
 
1643
        return PJ_SUCCESS;
 
1644
    else
 
1645
        return PJ_RETURN_OS_ERROR(pj_get_native_os_error());
 
1646
#else
 
1647
    pj_assert( sem == (pj_sem_t*)1 );
 
1648
    return PJ_SUCCESS;
 
1649
#endif
 
1650
}
 
1651
 
 
1652
/*
 
1653
 * pj_sem_post()
 
1654
 */
 
1655
PJ_DEF(pj_status_t) pj_sem_post(pj_sem_t *sem)
 
1656
{
 
1657
#if PJ_HAS_THREADS
 
1658
    int result;
 
1659
    PJ_LOG(6, (sem->obj_name, "Semaphore released by thread %s",
 
1660
                              pj_thread_this()->obj_name));
 
1661
    result = sem_post( sem->sem );
 
1662
 
 
1663
    if (result == 0)
 
1664
        return PJ_SUCCESS;
 
1665
    else
 
1666
        return PJ_RETURN_OS_ERROR(pj_get_native_os_error());
 
1667
#else
 
1668
    pj_assert( sem == (pj_sem_t*) 1);
 
1669
    return PJ_SUCCESS;
 
1670
#endif
 
1671
}
 
1672
 
 
1673
/*
 
1674
 * pj_sem_destroy()
 
1675
 */
 
1676
PJ_DEF(pj_status_t) pj_sem_destroy(pj_sem_t *sem)
 
1677
{
 
1678
#if PJ_HAS_THREADS
 
1679
    int result;
 
1680
 
 
1681
    PJ_CHECK_STACK();
 
1682
    PJ_ASSERT_RETURN(sem, PJ_EINVAL);
 
1683
 
 
1684
    PJ_LOG(6, (sem->obj_name, "Semaphore destroyed by thread %s",
 
1685
                              pj_thread_this()->obj_name));
 
1686
#if defined(PJ_DARWINOS) && PJ_DARWINOS!=0
 
1687
    result = sem_close( sem->sem );
 
1688
#else
 
1689
    result = sem_destroy( sem->sem );
 
1690
#endif
 
1691
 
 
1692
    if (result == 0)
 
1693
        return PJ_SUCCESS;
 
1694
    else
 
1695
        return PJ_RETURN_OS_ERROR(pj_get_native_os_error());
 
1696
#else
 
1697
    pj_assert( sem == (pj_sem_t*) 1 );
 
1698
    return PJ_SUCCESS;
 
1699
#endif
 
1700
}
 
1701
 
 
1702
#endif  /* PJ_HAS_SEMAPHORE */
 
1703
 
 
1704
///////////////////////////////////////////////////////////////////////////////
 
1705
#if defined(PJ_HAS_EVENT_OBJ) && PJ_HAS_EVENT_OBJ != 0
 
1706
 
 
1707
/*
 
1708
 * pj_event_create()
 
1709
 */
 
1710
PJ_DEF(pj_status_t) pj_event_create(pj_pool_t *pool, const char *name,
 
1711
                                    pj_bool_t manual_reset, pj_bool_t initial,
 
1712
                                    pj_event_t **ptr_event)
 
1713
{
 
1714
    pj_event_t *event;
 
1715
 
 
1716
    event = PJ_POOL_ALLOC_T(pool, pj_event_t);
 
1717
 
 
1718
    init_mutex(&event->mutex, name, PJ_MUTEX_SIMPLE);
 
1719
    pthread_cond_init(&event->cond, 0);
 
1720
    event->auto_reset = !manual_reset;
 
1721
    event->threads_waiting = 0;
 
1722
 
 
1723
    if (initial) {
 
1724
        event->state = EV_STATE_SET;
 
1725
        event->threads_to_release = 1;
 
1726
    } else {
 
1727
        event->state = EV_STATE_OFF;
 
1728
        event->threads_to_release = 0;
 
1729
    }
 
1730
 
 
1731
    *ptr_event = event;
 
1732
    return PJ_SUCCESS;
 
1733
}
 
1734
 
 
1735
static void event_on_one_release(pj_event_t *event)
 
1736
{
 
1737
    if (event->state == EV_STATE_SET) {
 
1738
        if (event->auto_reset) {
 
1739
            event->threads_to_release = 0;
 
1740
            event->state = EV_STATE_OFF;
 
1741
        } else {
 
1742
            /* Manual reset remains on */
 
1743
        }
 
1744
    } else {
 
1745
        if (event->auto_reset) {
 
1746
            /* Only release one */
 
1747
            event->threads_to_release = 0;
 
1748
            event->state = EV_STATE_OFF;
 
1749
        } else {
 
1750
            event->threads_to_release--;
 
1751
            pj_assert(event->threads_to_release >= 0);
 
1752
            if (event->threads_to_release==0)
 
1753
                event->state = EV_STATE_OFF;
 
1754
        }
 
1755
    }
 
1756
}
 
1757
 
 
1758
/*
 
1759
 * pj_event_wait()
 
1760
 */
 
1761
PJ_DEF(pj_status_t) pj_event_wait(pj_event_t *event)
 
1762
{
 
1763
    pthread_mutex_lock(&event->mutex.mutex);
 
1764
    event->threads_waiting++;
 
1765
    while (event->state == EV_STATE_OFF)
 
1766
        pthread_cond_wait(&event->cond, &event->mutex.mutex);
 
1767
    event->threads_waiting--;
 
1768
    event_on_one_release(event);
 
1769
    pthread_mutex_unlock(&event->mutex.mutex);
 
1770
    return PJ_SUCCESS;
 
1771
}
 
1772
 
 
1773
/*
 
1774
 * pj_event_trywait()
 
1775
 */
 
1776
PJ_DEF(pj_status_t) pj_event_trywait(pj_event_t *event)
 
1777
{
 
1778
    pj_status_t status;
 
1779
 
 
1780
    pthread_mutex_lock(&event->mutex.mutex);
 
1781
    status = event->state != EV_STATE_OFF ? PJ_SUCCESS : -1;
 
1782
    if (status==PJ_SUCCESS) {
 
1783
        event_on_one_release(event);
 
1784
    }
 
1785
    pthread_mutex_unlock(&event->mutex.mutex);
 
1786
 
 
1787
    return status;
 
1788
}
 
1789
 
 
1790
/*
 
1791
 * pj_event_set()
 
1792
 */
 
1793
PJ_DEF(pj_status_t) pj_event_set(pj_event_t *event)
 
1794
{
 
1795
    pthread_mutex_lock(&event->mutex.mutex);
 
1796
    event->threads_to_release = 1;
 
1797
    event->state = EV_STATE_SET;
 
1798
    if (event->auto_reset)
 
1799
        pthread_cond_signal(&event->cond);
 
1800
    else
 
1801
        pthread_cond_broadcast(&event->cond);
 
1802
    pthread_mutex_unlock(&event->mutex.mutex);
 
1803
    return PJ_SUCCESS;
 
1804
}
 
1805
 
 
1806
/*
 
1807
 * pj_event_pulse()
 
1808
 */
 
1809
PJ_DEF(pj_status_t) pj_event_pulse(pj_event_t *event)
 
1810
{
 
1811
    pthread_mutex_lock(&event->mutex.mutex);
 
1812
    if (event->threads_waiting) {
 
1813
        event->threads_to_release = event->auto_reset ? 1 :
 
1814
                                        event->threads_waiting;
 
1815
        event->state = EV_STATE_PULSED;
 
1816
        if (event->threads_to_release==1)
 
1817
            pthread_cond_signal(&event->cond);
 
1818
        else
 
1819
            pthread_cond_broadcast(&event->cond);
 
1820
    }
 
1821
    pthread_mutex_unlock(&event->mutex.mutex);
 
1822
    return PJ_SUCCESS;
 
1823
}
 
1824
 
 
1825
/*
 
1826
 * pj_event_reset()
 
1827
 */
 
1828
PJ_DEF(pj_status_t) pj_event_reset(pj_event_t *event)
 
1829
{
 
1830
    pthread_mutex_lock(&event->mutex.mutex);
 
1831
    event->state = EV_STATE_OFF;
 
1832
    event->threads_to_release = 0;
 
1833
    pthread_mutex_unlock(&event->mutex.mutex);
 
1834
    return PJ_SUCCESS;
 
1835
}
 
1836
 
 
1837
/*
 
1838
 * pj_event_destroy()
 
1839
 */
 
1840
PJ_DEF(pj_status_t) pj_event_destroy(pj_event_t *event)
 
1841
{
 
1842
    pj_mutex_destroy(&event->mutex);
 
1843
    pthread_cond_destroy(&event->cond);
 
1844
    return PJ_SUCCESS;
 
1845
}
 
1846
 
 
1847
#endif  /* PJ_HAS_EVENT_OBJ */
 
1848
 
 
1849
///////////////////////////////////////////////////////////////////////////////
 
1850
#if defined(PJ_TERM_HAS_COLOR) && PJ_TERM_HAS_COLOR != 0
 
1851
/*
 
1852
 * Terminal
 
1853
 */
 
1854
 
 
1855
/**
 
1856
 * Set terminal color.
 
1857
 */
 
1858
PJ_DEF(pj_status_t) pj_term_set_color(pj_color_t color)
 
1859
{
 
1860
    /* put bright prefix to ansi_color */
 
1861
    char ansi_color[12] = "\033[01;3";
 
1862
 
 
1863
    if (color & PJ_TERM_COLOR_BRIGHT) {
 
1864
        color ^= PJ_TERM_COLOR_BRIGHT;
 
1865
    } else {
 
1866
        strcpy(ansi_color, "\033[00;3");
 
1867
    }
 
1868
 
 
1869
    switch (color) {
 
1870
    case 0:
 
1871
        /* black color */
 
1872
        strcat(ansi_color, "0m");
 
1873
        break;
 
1874
    case PJ_TERM_COLOR_R:
 
1875
        /* red color */
 
1876
        strcat(ansi_color, "1m");
 
1877
        break;
 
1878
    case PJ_TERM_COLOR_G:
 
1879
        /* green color */
 
1880
        strcat(ansi_color, "2m");
 
1881
        break;
 
1882
    case PJ_TERM_COLOR_B:
 
1883
        /* blue color */
 
1884
        strcat(ansi_color, "4m");
 
1885
        break;
 
1886
    case PJ_TERM_COLOR_R | PJ_TERM_COLOR_G:
 
1887
        /* yellow color */
 
1888
        strcat(ansi_color, "3m");
 
1889
        break;
 
1890
    case PJ_TERM_COLOR_R | PJ_TERM_COLOR_B:
 
1891
        /* magenta color */
 
1892
        strcat(ansi_color, "5m");
 
1893
        break;
 
1894
    case PJ_TERM_COLOR_G | PJ_TERM_COLOR_B:
 
1895
        /* cyan color */
 
1896
        strcat(ansi_color, "6m");
 
1897
        break;
 
1898
    case PJ_TERM_COLOR_R | PJ_TERM_COLOR_G | PJ_TERM_COLOR_B:
 
1899
        /* white color */
 
1900
        strcat(ansi_color, "7m");
 
1901
        break;
 
1902
    default:
 
1903
        /* default console color */
 
1904
        strcpy(ansi_color, "\033[00m");
 
1905
        break;
 
1906
    }
 
1907
 
 
1908
    fputs(ansi_color, stdout);
 
1909
 
 
1910
    return PJ_SUCCESS;
 
1911
}
 
1912
 
 
1913
/**
 
1914
 * Get current terminal foreground color.
 
1915
 */
 
1916
PJ_DEF(pj_color_t) pj_term_get_color(void)
 
1917
{
 
1918
    return 0;
 
1919
}
 
1920
 
 
1921
#endif  /* PJ_TERM_HAS_COLOR */
 
1922
 
 
1923
#if !defined(PJ_DARWINOS) || PJ_DARWINOS == 0
 
1924
/*
 
1925
 * pj_run_app()
 
1926
 */
 
1927
PJ_DEF(int) pj_run_app(pj_main_func_ptr main_func, int argc, char *argv[],
 
1928
                       unsigned flags)
 
1929
{
 
1930
    return (*main_func)(argc, argv);
 
1931
}
 
1932
#endif