Various fixes for OS X
[asterisk/asterisk.git] / main / sem.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2013, Digium, Inc.
5  *
6  * David M. Lee, II <dlee@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  *
21  * \brief Asterisk semaphore support.
22  */
23
24 #include "asterisk.h"
25
26 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
27
28 #include "asterisk/sem.h"
29 #include "asterisk/utils.h"
30
31 #ifndef HAS_WORKING_SEMAPHORE
32
33 /* DIY semaphores! */
34
35 int ast_sem_init(struct ast_sem *sem, int pshared, unsigned int value)
36 {
37         if (pshared) {
38                 /* Don't need it... yet */
39                 errno = ENOSYS;
40                 return -1;
41         }
42
43         /* Since value is unsigned, this will also catch attempts to init with
44          * a negative value */
45         if (value > AST_SEM_VALUE_MAX) {
46                 errno = EINVAL;
47                 return -1;
48         }
49
50         sem->count = value;
51         sem->waiters = 0;
52         ast_mutex_init(&sem->mutex);
53         ast_cond_init(&sem->cond, NULL);
54         return 0;
55 }
56
57 int ast_sem_destroy(struct ast_sem *sem)
58 {
59         ast_mutex_destroy(&sem->mutex);
60         ast_cond_destroy(&sem->cond);
61         return 0;
62 }
63
64 int ast_sem_post(struct ast_sem *sem)
65 {
66         SCOPED_MUTEX(lock, &sem->mutex);
67
68         ast_assert(sem->count >= 0);
69
70         if (sem->count == AST_SEM_VALUE_MAX) {
71                 errno = EOVERFLOW;
72                 return -1;
73         }
74
75         /* Give it up! */
76         ++sem->count;
77
78         /* Release a waiter, if needed */
79         if (sem->waiters) {
80                 ast_cond_signal(&sem->cond);
81         }
82
83         return 0;
84 }
85
86 int ast_sem_wait(struct ast_sem *sem)
87 {
88         int res;
89         SCOPED_MUTEX(lock, &sem->mutex);
90
91         ast_assert(sem->count >= 0);
92
93         /* Wait for a non-zero count */
94         ++sem->waiters;
95         while (sem->count == 0) {
96                 res = ast_cond_wait(&sem->cond, &sem->mutex);
97                 /* Give up on error */
98                 if (res != 0) {
99                         --sem->waiters;
100                         return res;
101                 }
102         }
103         --sem->waiters;
104
105         /* Take it! */
106         --sem->count;
107
108         return 0;
109 }
110
111 int ast_sem_timedwait(struct ast_sem *sem, const struct timespec *abs_timeout)
112 {
113         int res;
114         SCOPED_MUTEX(lock, &sem->mutex);
115
116         ast_assert(sem->count >= 0);
117
118         /* Wait for a non-zero count */
119         ++sem->waiters;
120         while (sem->count == 0) {
121                 res = ast_cond_timedwait(&sem->cond, &sem->mutex, abs_timeout);
122                 /* Give up on error */
123                 if (res != 0) {
124                         --sem->waiters;
125                         return res;
126                 }
127         }
128         --sem->waiters;
129
130         /* Take it! */
131         --sem->count;
132
133         return 0;
134 }
135
136 int ast_sem_getvalue(struct ast_sem *sem, int *sval)
137 {
138         SCOPED_MUTEX(lock, &sem->mutex);
139
140         ast_assert(sem->count >= 0);
141
142         *sval = sem->count;
143
144         return 0;
145 }
146
147 #endif