~ubuntu-branches/ubuntu/vivid/sflphone/vivid

« back to all changes in this revision

Viewing changes to daemon/libs/pjproject-2.0.1/pjlib/src/pj/os_core_linux_kernel.c

  • Committer: Package Import Robot
  • Author(s): Mark Purcell
  • Date: 2013-06-30 11:40:56 UTC
  • mfrom: (4.1.18 saucy-proposed)
  • Revision ID: package-import@ubuntu.com-20130630114056-0np50jkyqo6vnmii
Tags: 1.2.3-2
* changeset_r92d62cfc54732bbbcfff2b1d36c096b120b981a5.diff 
  - fixes automatic endian detection 
* Update Vcs: fixes vcs-field-not-canonical

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: os_core_linux_kernel.c 3553 2011-05-05 06:14:19Z nanang $ */
 
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/assert.h>
 
22
#include <pj/pool.h>
 
23
#include <pj/log.h>
 
24
#include <pj/except.h>
 
25
#include <pj/errno.h>
 
26
#include <pj/string.h>
 
27
#include <pj/compat/high_precision.h>
 
28
#include <pj/compat/sprintf.h>
 
29
 
 
30
#include <linux/config.h>
 
31
#include <linux/version.h>
 
32
#if defined(MODVERSIONS)
 
33
#include <linux/modversions.h>
 
34
#endif
 
35
#include <linux/kernel.h>
 
36
#include <linux/sched.h>
 
37
//#include <linux/tqueue.h>
 
38
#include <linux/wait.h>
 
39
#include <linux/signal.h>
 
40
 
 
41
#include <asm/atomic.h>
 
42
#include <asm/unistd.h>
 
43
#include <asm/semaphore.h>
 
44
 
 
45
#define THIS_FILE   "oslinuxkern"
 
46
 
 
47
struct pj_thread_t
 
48
{
 
49
    /** Thread's name. */
 
50
    char obj_name[PJ_MAX_OBJ_NAME];
 
51
 
 
52
    /** Linux task structure for thread. */
 
53
    struct task_struct *thread;
 
54
 
 
55
    /** Flags (specified in pj_thread_create) */
 
56
    unsigned flags;
 
57
 
 
58
    /** Task queue needed to launch thread. */
 
59
    //struct tq_struct  tq;
 
60
 
 
61
    /** Semaphore needed to control thread startup. */
 
62
    struct semaphore    startstop_sem;
 
63
 
 
64
    /** Semaphore to suspend thread during startup. */
 
65
    struct semaphore    suspend_sem;
 
66
 
 
67
    /** Queue thread is waiting on. Gets initialized by
 
68
        thread_initialize, can be used by thread itself.
 
69
     */
 
70
    wait_queue_head_t   queue;
 
71
 
 
72
    /** Flag to tell thread whether to die or not.
 
73
        When the thread receives a signal, it must check
 
74
        the value of terminate and call thread_deinitialize and terminate
 
75
        if set.
 
76
     */
 
77
    int terminate;
 
78
 
 
79
    /** Thread's entry. */
 
80
    pj_thread_proc *func;
 
81
 
 
82
    /** Argument. */
 
83
    void *arg;
 
84
};
 
85
 
 
86
struct pj_atomic_t
 
87
{
 
88
    atomic_t atom;
 
89
};
 
90
 
 
91
struct pj_mutex_t
 
92
{
 
93
    struct semaphore sem;
 
94
    pj_bool_t        recursive;
 
95
    pj_thread_t     *owner;
 
96
    int              own_count;
 
97
};
 
98
 
 
99
struct pj_sem_t
 
100
{
 
101
    struct semaphore sem;
 
102
};
 
103
 
 
104
/*
 
105
 * Static global variables.
 
106
 */
 
107
#define MAX_TLS_ID  32
 
108
static void *tls_values[MAX_TLS_ID];
 
109
static int tls_id;
 
110
static long thread_tls_id;
 
111
static spinlock_t critical_section = SPIN_LOCK_UNLOCKED;
 
112
static unsigned long spinlock_flags;
 
113
static pj_thread_t main_thread;
 
114
 
 
115
/* private functions */
 
116
//#define TRACE_(expr)  PJ_LOG(3,expr)
 
117
#define TRACE_(x)
 
118
 
 
119
 
 
120
/* This must be called in the context of the new thread. */
 
121
static void thread_initialize( pj_thread_t *thread )
 
122
{
 
123
    TRACE_((THIS_FILE, "---new thread initializing..."));
 
124
 
 
125
    /* Set TLS */
 
126
    pj_thread_local_set(thread_tls_id, thread);
 
127
 
 
128
    /* fill in thread structure */
 
129
    thread->thread = current;
 
130
    pj_assert(thread->thread != NULL);
 
131
 
 
132
    /* set signal mask to what we want to respond */
 
133
    siginitsetinv(&current->blocked,
 
134
                  sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM));
 
135
 
 
136
    /* initialise wait queue */
 
137
    init_waitqueue_head(&thread->queue);
 
138
 
 
139
    /* initialise termination flag */
 
140
    thread->terminate = 0;
 
141
 
 
142
    /* set name of this process (making sure obj_name is null
 
143
     * terminated first)
 
144
     */
 
145
    thread->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
 
146
    sprintf(current->comm, thread->obj_name);
 
147
 
 
148
    /* tell the creator that we are ready and let him continue */
 
149
    up(&thread->startstop_sem);
 
150
}
 
151
 
 
152
/* cleanup of thread. Called by the exiting thread. */
 
153
static void thread_deinitialize(pj_thread_t *thread)
 
154
{
 
155
    /* we are terminating */
 
156
 
 
157
    /* lock the kernel, the exit will unlock it */
 
158
    thread->thread = NULL;
 
159
    mb();
 
160
 
 
161
    /* notify the stop_kthread() routine that we are terminating. */
 
162
    up(&thread->startstop_sem);
 
163
 
 
164
    /* the kernel_thread that called clone() does a do_exit here. */
 
165
 
 
166
    /* there is no race here between execution of the "killer" and
 
167
       real termination of the thread (race window between up and do_exit),
 
168
       since both the thread and the "killer" function are running with
 
169
       the kernel lock held.
 
170
       The kernel lock will be freed after the thread exited, so the code
 
171
       is really not executed anymore as soon as the unload functions gets
 
172
       the kernel lock back.
 
173
       The init process may not have made the cleanup of the process here,
 
174
       but the cleanup can be done safely with the module unloaded.
 
175
    */
 
176
 
 
177
}
 
178
 
 
179
static int thread_proc(void *arg)
 
180
{
 
181
    pj_thread_t *thread = arg;
 
182
 
 
183
    TRACE_((THIS_FILE, "---new thread starting!"));
 
184
 
 
185
    /* Initialize thread. */
 
186
    thread_initialize( thread );
 
187
 
 
188
    /* Wait if created suspended. */
 
189
    if (thread->flags & PJ_THREAD_SUSPENDED) {
 
190
        TRACE_((THIS_FILE, "---new thread suspended..."));
 
191
        down(&thread->suspend_sem);
 
192
    }
 
193
 
 
194
    TRACE_((THIS_FILE, "---new thread running..."));
 
195
 
 
196
    pj_assert(thread->func != NULL);
 
197
 
 
198
    /* Call thread's entry. */
 
199
    (*thread->func)(thread->arg);
 
200
 
 
201
    TRACE_((THIS_FILE, "---thread exiting..."));
 
202
 
 
203
    /* Cleanup thread. */
 
204
    thread_deinitialize(thread);
 
205
 
 
206
    return 0;
 
207
}
 
208
 
 
209
/* The very task entry. */
 
210
static void kthread_launcher(void *arg)
 
211
{
 
212
    TRACE_((THIS_FILE, "...launching thread!..."));
 
213
    kernel_thread(&thread_proc, arg, 0);
 
214
}
 
215
 
 
216
PJ_DEF(pj_status_t) pj_init(void)
 
217
{
 
218
    pj_status_t rc;
 
219
 
 
220
    PJ_LOG(5, ("pj_init", "Initializing PJ Library.."));
 
221
 
 
222
    rc = pj_thread_init();
 
223
    if (rc != PJ_SUCCESS)
 
224
        return rc;
 
225
 
 
226
    /* Initialize exception ID for the pool.
 
227
     * Must do so after critical section is configured.
 
228
     */
 
229
    rc = pj_exception_id_alloc("PJLIB/No memory", &PJ_NO_MEMORY_EXCEPTION);
 
230
    if (rc != PJ_SUCCESS)
 
231
        return rc;
 
232
 
 
233
    return PJ_SUCCESS;
 
234
}
 
235
 
 
236
PJ_DEF(pj_uint32_t) pj_getpid(void)
 
237
{
 
238
    return 1;
 
239
}
 
240
 
 
241
PJ_DEF(pj_status_t) pj_thread_register ( const char *cstr_thread_name,
 
242
                                         pj_thread_desc desc,
 
243
                                         pj_thread_t **ptr_thread)
 
244
{
 
245
    char stack_ptr;
 
246
    pj_thread_t *thread = (pj_thread_t *)desc;
 
247
    pj_str_t thread_name = pj_str((char*)cstr_thread_name);
 
248
 
 
249
    /* Size sanity check. */
 
250
    if (sizeof(pj_thread_desc) < sizeof(pj_thread_t)) {
 
251
        pj_assert(!"Not enough pj_thread_desc size!");
 
252
        return PJ_EBUG;
 
253
    }
 
254
 
 
255
    /* If a thread descriptor has been registered before, just return it. */
 
256
    if (pj_thread_local_get (thread_tls_id) != 0) {
 
257
        // 2006-02-26 bennylp:
 
258
        //  This wouldn't work in all cases!.
 
259
        //  If thread is created by external module (e.g. sound thread),
 
260
        //  thread may be reused while the pool used for the thread descriptor
 
261
        //  has been deleted by application.
 
262
        //*thread_ptr = (pj_thread_t*)pj_thread_local_get (thread_tls_id);
 
263
        //return PJ_SUCCESS;
 
264
    }
 
265
 
 
266
    /* Initialize and set the thread entry. */
 
267
    pj_bzero(desc, sizeof(struct pj_thread_t));
 
268
 
 
269
    if(cstr_thread_name && pj_strlen(&thread_name) < sizeof(thread->obj_name)-1)
 
270
        pj_sprintf(thread->obj_name, cstr_thread_name, thread->thread);
 
271
    else
 
272
        pj_snprintf(thread->obj_name, sizeof(thread->obj_name),
 
273
                    "thr%p", (void*)thread->thread);
 
274
 
 
275
    /* Initialize. */
 
276
    thread_initialize(thread);
 
277
 
 
278
    /* Eat semaphore. */
 
279
    down(&thread->startstop_sem);
 
280
 
 
281
#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
 
282
    thread->stk_start = &stack_ptr;
 
283
    thread->stk_size = 0xFFFFFFFFUL;
 
284
    thread->stk_max_usage = 0;
 
285
#else
 
286
    stack_ptr = '\0';
 
287
#endif
 
288
 
 
289
    *ptr_thread = thread;
 
290
    return PJ_SUCCESS;
 
291
}
 
292
 
 
293
 
 
294
pj_status_t pj_thread_init(void)
 
295
{
 
296
    pj_status_t rc;
 
297
    pj_thread_t *dummy;
 
298
 
 
299
    rc = pj_thread_local_alloc(&thread_tls_id);
 
300
    if (rc != PJ_SUCCESS)
 
301
        return rc;
 
302
 
 
303
    return pj_thread_register("pjlib-main", (long*)&main_thread, &dummy);
 
304
}
 
305
 
 
306
PJ_DEF(pj_status_t) pj_thread_create( pj_pool_t *pool, const char *thread_name,
 
307
                                      pj_thread_proc *proc, void *arg,
 
308
                                      pj_size_t stack_size, unsigned flags,
 
309
                                      pj_thread_t **ptr_thread)
 
310
{
 
311
    pj_thread_t *thread;
 
312
 
 
313
    TRACE_((THIS_FILE, "pj_thread_create()"));
 
314
 
 
315
    PJ_ASSERT_RETURN(pool && proc && ptr_thread, PJ_EINVAL);
 
316
 
 
317
    thread = pj_pool_zalloc(pool, sizeof(pj_thread_t));
 
318
    if (!thread)
 
319
        return PJ_ENOMEM;
 
320
 
 
321
    PJ_UNUSED_ARG(stack_size);
 
322
 
 
323
    /* Thread name. */
 
324
    if (!thread_name)
 
325
        thread_name = "thr%p";
 
326
 
 
327
    if (strchr(thread_name, '%')) {
 
328
        pj_snprintf(thread->obj_name, PJ_MAX_OBJ_NAME, thread_name, thread);
 
329
    } else {
 
330
        strncpy(thread->obj_name, thread_name, PJ_MAX_OBJ_NAME);
 
331
        thread->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
 
332
    }
 
333
 
 
334
    /* Init thread's semaphore. */
 
335
    TRACE_((THIS_FILE, "...init semaphores..."));
 
336
    init_MUTEX_LOCKED(&thread->startstop_sem);
 
337
    init_MUTEX_LOCKED(&thread->suspend_sem);
 
338
 
 
339
    thread->flags = flags;
 
340
 
 
341
    if ((flags & PJ_THREAD_SUSPENDED) == 0) {
 
342
        up(&thread->suspend_sem);
 
343
    }
 
344
 
 
345
    /* Store the functions and argument. */
 
346
    thread->func = proc;
 
347
    thread->arg = arg;
 
348
 
 
349
    /* Save return value. */
 
350
    *ptr_thread = thread;
 
351
 
 
352
    /* Create the new thread by running a task through keventd. */
 
353
 
 
354
#if 0
 
355
    /* Initialize the task queue struct. */
 
356
    thread->tq.sync = 0;
 
357
    INIT_LIST_HEAD(&thread->tq.list);
 
358
    thread->tq.routine = kthread_launcher;
 
359
    thread->tq.data = thread;
 
360
 
 
361
    /* and schedule it for execution. */
 
362
    schedule_task(&thread->tq);
 
363
#endif
 
364
    kthread_launcher(thread);
 
365
 
 
366
    /* Wait until thread has reached the setup_thread routine. */
 
367
    TRACE_((THIS_FILE, "...wait for the new thread..."));
 
368
    down(&thread->startstop_sem);
 
369
 
 
370
    TRACE_((THIS_FILE, "...main thread resumed..."));
 
371
    return PJ_SUCCESS;
 
372
}
 
373
 
 
374
PJ_DEF(const char*) pj_thread_get_name(pj_thread_t *thread)
 
375
{
 
376
    return thread->obj_name;
 
377
}
 
378
 
 
379
PJ_DEF(pj_status_t) pj_thread_resume(pj_thread_t *thread)
 
380
{
 
381
    up(&thread->suspend_sem);
 
382
    return PJ_SUCCESS;
 
383
}
 
384
 
 
385
PJ_DEF(pj_thread_t*) pj_thread_this(void)
 
386
{
 
387
    return (pj_thread_t*)pj_thread_local_get(thread_tls_id);
 
388
}
 
389
 
 
390
PJ_DEF(pj_status_t) pj_thread_join(pj_thread_t *p)
 
391
{
 
392
    TRACE_((THIS_FILE, "pj_thread_join()"));
 
393
    down(&p->startstop_sem);
 
394
    TRACE_((THIS_FILE, "  joined!"));
 
395
    return PJ_SUCCESS;
 
396
}
 
397
 
 
398
PJ_DEF(pj_status_t) pj_thread_destroy(pj_thread_t *thread)
 
399
{
 
400
    PJ_ASSERT_RETURN(thread != NULL, PJ_EINVALIDOP);
 
401
    return PJ_SUCCESS;
 
402
}
 
403
 
 
404
PJ_DEF(pj_status_t) pj_thread_sleep(unsigned msec)
 
405
{
 
406
    pj_highprec_t ticks;
 
407
    pj_thread_t *thread = pj_thread_this();
 
408
 
 
409
    PJ_ASSERT_RETURN(thread != NULL, PJ_EBUG);
 
410
 
 
411
    /* Use high precision calculation to make sure we don't
 
412
     * crop values:
 
413
     *
 
414
     *  ticks = HZ * msec / 1000
 
415
     */
 
416
    ticks = HZ;
 
417
    pj_highprec_mul(ticks, msec);
 
418
    pj_highprec_div(ticks, 1000);
 
419
 
 
420
    TRACE_((THIS_FILE, "this thread will sleep for %u ticks", ticks));
 
421
    interruptible_sleep_on_timeout( &thread->queue, ticks);
 
422
    return PJ_SUCCESS;
 
423
}
 
424
 
 
425
 
 
426
///////////////////////////////////////////////////////////////////////////////
 
427
PJ_DEF(pj_status_t) pj_atomic_create( pj_pool_t *pool,
 
428
                                      pj_atomic_value_t value,
 
429
                                      pj_atomic_t **ptr_var)
 
430
{
 
431
    pj_atomic_t *t = pj_pool_calloc(pool, 1, sizeof(pj_atomic_t));
 
432
    if (!t) return PJ_ENOMEM;
 
433
 
 
434
    atomic_set(&t->atom, value);
 
435
    *ptr_var = t;
 
436
 
 
437
    return PJ_SUCCESS;
 
438
}
 
439
 
 
440
PJ_DEF(pj_status_t) pj_atomic_destroy( pj_atomic_t *var )
 
441
{
 
442
    return PJ_SUCCESS;
 
443
}
 
444
 
 
445
PJ_DEF(void) pj_atomic_set(pj_atomic_t *var, pj_atomic_value_t value)
 
446
{
 
447
    atomic_set(&var->atom, value);
 
448
}
 
449
 
 
450
PJ_DEF(pj_atomic_value_t) pj_atomic_get(pj_atomic_t *var)
 
451
{
 
452
    return atomic_read(&var->atom);
 
453
}
 
454
 
 
455
PJ_DEF(void) pj_atomic_inc(pj_atomic_t *var)
 
456
{
 
457
    atomic_inc(&var->atom);
 
458
}
 
459
 
 
460
PJ_DEF(void) pj_atomic_dec(pj_atomic_t *var)
 
461
{
 
462
    atomic_dec(&var->atom);
 
463
}
 
464
 
 
465
PJ_DEF(void) pj_atomic_add( pj_atomic_t *var, pj_atomic_value_t value )
 
466
{
 
467
    atomic_add(value, &var->atom);
 
468
}
 
469
 
 
470
 
 
471
///////////////////////////////////////////////////////////////////////////////
 
472
PJ_DEF(pj_status_t) pj_thread_local_alloc(long *index)
 
473
{
 
474
    if (tls_id >= MAX_TLS_ID)
 
475
        return PJ_ETOOMANY;
 
476
 
 
477
    *index = tls_id++;
 
478
 
 
479
    return PJ_SUCCESS;
 
480
}
 
481
 
 
482
PJ_DEF(void) pj_thread_local_free(long index)
 
483
{
 
484
    pj_assert(index >= 0 && index < MAX_TLS_ID);
 
485
}
 
486
 
 
487
PJ_DEF(pj_status_t) pj_thread_local_set(long index, void *value)
 
488
{
 
489
    pj_assert(index >= 0 && index < MAX_TLS_ID);
 
490
    tls_values[index] = value;
 
491
    return PJ_SUCCESS;
 
492
}
 
493
 
 
494
PJ_DEF(void*) pj_thread_local_get(long index)
 
495
{
 
496
    pj_assert(index >= 0 && index < MAX_TLS_ID);
 
497
    return tls_values[index];
 
498
}
 
499
 
 
500
 
 
501
///////////////////////////////////////////////////////////////////////////////
 
502
PJ_DEF(void) pj_enter_critical_section(void)
 
503
{
 
504
    spin_lock_irqsave(&critical_section, spinlock_flags);
 
505
}
 
506
 
 
507
PJ_DEF(void) pj_leave_critical_section(void)
 
508
{
 
509
    spin_unlock_irqrestore(&critical_section, spinlock_flags);
 
510
}
 
511
 
 
512
 
 
513
///////////////////////////////////////////////////////////////////////////////
 
514
PJ_DEF(pj_status_t) pj_mutex_create( pj_pool_t *pool,
 
515
                                     const char *name,
 
516
                                     int type,
 
517
                                     pj_mutex_t **ptr_mutex)
 
518
{
 
519
    pj_mutex_t *mutex;
 
520
 
 
521
    PJ_UNUSED_ARG(name);
 
522
 
 
523
    mutex = pj_pool_alloc(pool, sizeof(pj_mutex_t));
 
524
    if (!mutex)
 
525
        return PJ_ENOMEM;
 
526
 
 
527
    init_MUTEX(&mutex->sem);
 
528
 
 
529
    mutex->recursive = (type == PJ_MUTEX_RECURSE);
 
530
    mutex->owner = NULL;
 
531
    mutex->own_count = 0;
 
532
 
 
533
    /* Done. */
 
534
    *ptr_mutex = mutex;
 
535
    return PJ_SUCCESS;
 
536
}
 
537
 
 
538
PJ_DEF(pj_status_t) pj_mutex_create_simple( pj_pool_t *pool, const char *name,
 
539
                                            pj_mutex_t **mutex )
 
540
{
 
541
    return pj_mutex_create(pool, name, PJ_MUTEX_SIMPLE, mutex);
 
542
}
 
543
 
 
544
PJ_DEF(pj_status_t) pj_mutex_create_recursive( pj_pool_t *pool,
 
545
                                               const char *name,
 
546
                                               pj_mutex_t **mutex )
 
547
{
 
548
    return pj_mutex_create( pool, name, PJ_MUTEX_RECURSE, mutex);
 
549
}
 
550
 
 
551
PJ_DEF(pj_status_t) pj_mutex_lock(pj_mutex_t *mutex)
 
552
{
 
553
    PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
 
554
 
 
555
    if (mutex->recursive) {
 
556
        pj_thread_t *this_thread = pj_thread_this();
 
557
        if (mutex->owner == this_thread) {
 
558
            ++mutex->own_count;
 
559
        } else {
 
560
            down(&mutex->sem);
 
561
            pj_assert(mutex->own_count == 0);
 
562
            mutex->owner = this_thread;
 
563
            mutex->own_count = 1;
 
564
        }
 
565
    } else {
 
566
        down(&mutex->sem);
 
567
    }
 
568
    return PJ_SUCCESS;
 
569
}
 
570
 
 
571
PJ_DEF(pj_status_t) pj_mutex_trylock(pj_mutex_t *mutex)
 
572
{
 
573
    long rc;
 
574
 
 
575
    PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
 
576
 
 
577
    if (mutex->recursive) {
 
578
        pj_thread_t *this_thread = pj_thread_this();
 
579
        if (mutex->owner == this_thread) {
 
580
            ++mutex->own_count;
 
581
        } else {
 
582
            rc = down_interruptible(&mutex->sem);
 
583
            if (rc != 0)
 
584
                return PJ_RETURN_OS_ERROR(-rc);
 
585
            pj_assert(mutex->own_count == 0);
 
586
            mutex->owner = this_thread;
 
587
            mutex->own_count = 1;
 
588
        }
 
589
    } else {
 
590
        int rc = down_trylock(&mutex->sem);
 
591
        if (rc != 0)
 
592
            return PJ_RETURN_OS_ERROR(-rc);
 
593
    }
 
594
    return PJ_SUCCESS;
 
595
}
 
596
 
 
597
PJ_DEF(pj_status_t) pj_mutex_unlock(pj_mutex_t *mutex)
 
598
{
 
599
    PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
 
600
 
 
601
    if (mutex->recursive) {
 
602
        pj_thread_t *this_thread = pj_thread_this();
 
603
        if (mutex->owner == this_thread) {
 
604
            pj_assert(mutex->own_count > 0);
 
605
            --mutex->own_count;
 
606
            if (mutex->own_count == 0) {
 
607
                mutex->owner = NULL;
 
608
                up(&mutex->sem);
 
609
            }
 
610
        } else {
 
611
            pj_assert(!"Not owner!");
 
612
            return PJ_EINVALIDOP;
 
613
        }
 
614
    } else {
 
615
        up(&mutex->sem);
 
616
    }
 
617
    return PJ_SUCCESS;
 
618
}
 
619
 
 
620
PJ_DEF(pj_status_t) pj_mutex_destroy(pj_mutex_t *mutex)
 
621
{
 
622
    PJ_ASSERT_RETURN(mutex != NULL, PJ_EINVAL);
 
623
 
 
624
    return PJ_SUCCESS;
 
625
}
 
626
 
 
627
#if defined(PJ_DEBUG) && PJ_DEBUG != 0
 
628
PJ_DEF(pj_bool_t) pj_mutex_is_locked(pj_mutex_t *mutex)
 
629
{
 
630
    if (mutex->recursive)
 
631
        return mutex->owner == pj_thread_this();
 
632
    else
 
633
        return 1;
 
634
}
 
635
#endif  /* PJ_DEBUG */
 
636
 
 
637
 
 
638
#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0
 
639
 
 
640
PJ_DEF(pj_status_t) pj_sem_create(  pj_pool_t *pool,
 
641
                                    const char *name,
 
642
                                    unsigned initial,
 
643
                                    unsigned max,
 
644
                                    pj_sem_t **sem)
 
645
{
 
646
    pj_sem_t *sem;
 
647
 
 
648
    PJ_UNUSED_ARG(max);
 
649
 
 
650
    PJ_ASSERT_RETURN(pool && sem, PJ_EINVAL);
 
651
 
 
652
    sem = pj_pool_alloc(pool, sizeof(pj_sem_t));
 
653
    sema_init(&sem->sem, initial);
 
654
    return PJ_SUCCESS;
 
655
}
 
656
 
 
657
PJ_DEF(pj_status_t) pj_sem_wait(pj_sem_t *sem)
 
658
{
 
659
    PJ_ASSERT_RETURN(pool && sem, PJ_EINVAL);
 
660
 
 
661
    down(&sem->sem);
 
662
    return PJ_SUCCESS;
 
663
}
 
664
 
 
665
PJ_DEF(pj_status_t) pj_sem_trywait(pj_sem_t *sem)
 
666
{
 
667
    int rc;
 
668
 
 
669
    PJ_ASSERT_RETURN(pool && sem, PJ_EINVAL);
 
670
 
 
671
    rc = down_trylock(&sem->sem);
 
672
    if (rc != 0) {
 
673
        return PJ_RETURN_OS_ERROR(-rc);
 
674
    } else {
 
675
        return PJ_SUCCESS;
 
676
    }
 
677
}
 
678
 
 
679
PJ_DEF(pj_status_t) pj_sem_post(pj_sem_t *sem)
 
680
{
 
681
    PJ_ASSERT_RETURN(pool && sem, PJ_EINVAL);
 
682
 
 
683
    up(&sem->sem);
 
684
    return PJ_SUCCESS;
 
685
}
 
686
 
 
687
PJ_DEF(pj_status_t) pj_sem_destroy(pj_sem_t *sem)
 
688
{
 
689
    PJ_ASSERT_RETURN(pool && sem, PJ_EINVAL);
 
690
 
 
691
    return PJ_SUCCESS;
 
692
}
 
693
 
 
694
#endif  /* PJ_HAS_SEMAPHORE */