root / trunk / code / projects / colonet / server / vision / sysvsem.cpp @ 1428
History | View | Annotate | Download (8.92 KB)
1 | 939 | rcahoon | /*
|
---|---|---|---|
2 | +----------------------------------------------------------------------+
|
||
3 | | PHP Version 5 |
|
||
4 | +----------------------------------------------------------------------+
|
||
5 | | Copyright (c) 1997-2008 The PHP Group |
|
||
6 | +----------------------------------------------------------------------+
|
||
7 | | This source file is subject to version 3.01 of the PHP license, |
|
||
8 | | that is bundled with this package in the file LICENSE, and is |
|
||
9 | | available through the world-wide-web at the following url: |
|
||
10 | | http://www.php.net/license/3_01.txt |
|
||
11 | | If you did not receive a copy of the PHP license and are unable to |
|
||
12 | | obtain it through the world-wide-web, please send a note to |
|
||
13 | | license@php.net so we can mail you a copy immediately. |
|
||
14 | +----------------------------------------------------------------------+
|
||
15 | | Authors: Tom May <tom@go2net.com> |
|
||
16 | | Gavin Sherry <gavin@linuxworld.com.au> |
|
||
17 | +----------------------------------------------------------------------+
|
||
18 | */
|
||
19 | |||
20 | /* $Id: sysvsem.c,v 1.51.2.3.2.3 2007/12/31 07:20:13 sebastian Exp $ */
|
||
21 | |||
22 | /* Latest update build anc tested on Linux 2.2.14
|
||
23 | *
|
||
24 | * This has been built and tested on Solaris 2.6 and Linux 2.1.122.
|
||
25 | * It may not compile or execute correctly on other systems.
|
||
26 | *
|
||
27 | * sas: Works for me on Linux 2.0.36 and FreeBSD 3.0-current
|
||
28 | */
|
||
29 | |||
30 | #include <sys/types.h> |
||
31 | #include <sys/ipc.h> |
||
32 | #include <sys/sem.h> |
||
33 | #include <errno.h> |
||
34 | |||
35 | #include <string.h> |
||
36 | #include <stdio.h> |
||
37 | #include <stdlib.h> |
||
38 | |||
39 | #include <php/main/php_config.h> |
||
40 | |||
41 | #include "php_sysvsem.h" |
||
42 | |||
43 | #if !HAVE_SEMUN
|
||
44 | |||
45 | union semun {
|
||
46 | int val; /* value for SETVAL */ |
||
47 | struct semid_ds *buf; /* buffer for IPC_STAT, IPC_SET */ |
||
48 | unsigned short int *array; /* array for GETALL, SETALL */ |
||
49 | struct seminfo *__buf; /* buffer for IPC_INFO */ |
||
50 | }; |
||
51 | |||
52 | #undef HAVE_SEMUN
|
||
53 | #define HAVE_SEMUN 1 |
||
54 | |||
55 | #endif
|
||
56 | |||
57 | /* Semaphore functions using System V semaphores. Each semaphore
|
||
58 | * actually consists of three semaphores allocated as a unit under the
|
||
59 | * same key. Semaphore 0 (SYSVSEM_SEM) is the actual semaphore, it is
|
||
60 | * initialized to max_acquire and decremented as processes acquire it.
|
||
61 | * The value of semaphore 1 (SYSVSEM_USAGE) is a count of the number
|
||
62 | * of processes using the semaphore. After calling semget(), if a
|
||
63 | * process finds that the usage count is 1, it will set the value of
|
||
64 | * SYSVSEM_SEM to max_acquire. This allows max_acquire to be set and
|
||
65 | * track the PHP code without having a global init routine or external
|
||
66 | * semaphore init code. Except see the bug regarding a race condition
|
||
67 | * php_sysvsem_get(). Semaphore 2 (SYSVSEM_SETVAL) serializes the
|
||
68 | * calls to GETVAL SYSVSEM_USAGE and SETVAL SYSVSEM_SEM. It can be
|
||
69 | * acquired only when it is zero.
|
||
70 | */
|
||
71 | |||
72 | #define SYSVSEM_SEM 0 |
||
73 | #define SYSVSEM_USAGE 1 |
||
74 | #define SYSVSEM_SETVAL 2 |
||
75 | |||
76 | /* {{{ release_sysvsem_sem
|
||
77 | */
|
||
78 | sysvsem::~sysvsem() |
||
79 | { |
||
80 | struct sembuf sop[2]; |
||
81 | int opcount = 1; |
||
82 | |||
83 | /* Decrement the usage count. */
|
||
84 | sop[0].sem_num = SYSVSEM_USAGE;
|
||
85 | sop[0].sem_op = -1; |
||
86 | sop[0].sem_flg = SEM_UNDO;
|
||
87 | /* Release the semaphore if it has been acquired but not released. */
|
||
88 | if (this->count) { |
||
89 | sop[1].sem_num = SYSVSEM_SEM;
|
||
90 | sop[1].sem_op = this->count; |
||
91 | sop[1].sem_flg = SEM_UNDO;
|
||
92 | |||
93 | opcount++; |
||
94 | } |
||
95 | |||
96 | semop(this->semid, sop, opcount);
|
||
97 | |||
98 | |||
99 | //TODO: Need to auto remove() semaphore when SYSVSEM_USAGE is 0
|
||
100 | |||
101 | //efree(sem_ptr);
|
||
102 | } |
||
103 | /* }}} */
|
||
104 | #define SETVAL_WANTS_PTR
|
||
105 | |||
106 | #if defined(_AIX)
|
||
107 | #undef SETVAL_WANTS_PTR
|
||
108 | #endif
|
||
109 | |||
110 | /* {{{ proto resource sem_get(int key [, int max_acquire [, int perm [, int auto_release]])
|
||
111 | Return an id for the semaphore with the given key, and allow max_acquire (default 1) processes to acquire it simultaneously */
|
||
112 | /* max_aquire = 1, perm = 0666, auto_release = 1 */
|
||
113 | sysvsem::sysvsem(long key, long max_acquire, long perm, long auto_release) throw (sysvsem_error) |
||
114 | { |
||
115 | int semid;
|
||
116 | struct sembuf sop[3]; |
||
117 | int count;
|
||
118 | |||
119 | /* Get/create the semaphore. Note that we rely on the semaphores
|
||
120 | * being zeroed when they are created. Despite the fact that
|
||
121 | * the(?) Linux semget() man page says they are not initialized,
|
||
122 | * the kernel versions 2.0.x and 2.1.z do in fact zero them.
|
||
123 | */
|
||
124 | |||
125 | semid = semget(key, 3, perm|IPC_CREAT);
|
||
126 | if (semid == -1) { |
||
127 | fprintf(stderr, "%s failed for key 0x%lx: %s\n", __FUNCTION__, key, strerror(errno));
|
||
128 | throw sysvsem_error("failed to open semaphore"); |
||
129 | } |
||
130 | |||
131 | /* Find out how many processes are using this semaphore. Note
|
||
132 | * that on Linux (at least) there is a race condition here because
|
||
133 | * semaphore undo on process exit is not atomic, so we could
|
||
134 | * acquire SYSVSEM_SETVAL before a crashed process has decremented
|
||
135 | * SYSVSEM_USAGE in which case count will be greater than it
|
||
136 | * should be and we won't set max_acquire. Fortunately this
|
||
137 | * doesn't actually matter in practice.
|
||
138 | */
|
||
139 | |||
140 | /* Wait for sem 1 to be zero . . . */
|
||
141 | |||
142 | sop[0].sem_num = SYSVSEM_SETVAL;
|
||
143 | sop[0].sem_op = 0; |
||
144 | sop[0].sem_flg = 0; |
||
145 | |||
146 | /* . . . and increment it so it becomes non-zero . . . */
|
||
147 | |||
148 | sop[1].sem_num = SYSVSEM_SETVAL;
|
||
149 | sop[1].sem_op = 1; |
||
150 | sop[1].sem_flg = SEM_UNDO;
|
||
151 | |||
152 | /* . . . and increment the usage count. */
|
||
153 | |||
154 | sop[2].sem_num = SYSVSEM_USAGE;
|
||
155 | sop[2].sem_op = 1; |
||
156 | sop[2].sem_flg = SEM_UNDO;
|
||
157 | while (semop(semid, sop, 3) == -1) { |
||
158 | if (errno != EINTR) {
|
||
159 | fprintf(stderr, "%s failed acquiring SYSVSEM_SETVAL for key 0x%lx: %s\n", __FUNCTION__, key, strerror(errno));
|
||
160 | break;
|
||
161 | } |
||
162 | } |
||
163 | |||
164 | /* Get the usage count. */
|
||
165 | count = semctl(semid, SYSVSEM_USAGE, GETVAL, NULL);
|
||
166 | if (count == -1) { |
||
167 | fprintf(stderr, "%s failed for key 0x%lx: %s\n", __FUNCTION__, key, strerror(errno));
|
||
168 | } |
||
169 | |||
170 | printf("proc count: %d\n", count);
|
||
171 | |||
172 | /* If we are the only user, then take this opportunity to set the max. */
|
||
173 | |||
174 | if (count == 1) { |
||
175 | #if HAVE_SEMUN
|
||
176 | /* This is correct for Linux which has union semun. */
|
||
177 | union semun semarg;
|
||
178 | semarg.val = max_acquire; |
||
179 | if (semctl(semid, SYSVSEM_SEM, SETVAL, semarg) == -1) { |
||
180 | fprintf(stderr, "%s failed for key 0x%lx: %s\n", __FUNCTION__, key, strerror(errno));
|
||
181 | } |
||
182 | #elif defined(SETVAL_WANTS_PTR)
|
||
183 | /* This is correct for Solaris 2.6 which does not have union semun. */
|
||
184 | if (semctl(semid, SYSVSEM_SEM, SETVAL, &max_acquire) == -1) { |
||
185 | fprintf(stderr, "%s failed for key 0x%lx: %s\n", __FUNCTION__, key, strerror(errno));
|
||
186 | } |
||
187 | #else
|
||
188 | /* This works for i.e. AIX */
|
||
189 | if (semctl(semid, SYSVSEM_SEM, SETVAL, max_acquire) == -1) { |
||
190 | fprintf(stderr, "%s failed for key 0x%lx: %s\n", __FUNCTION__, key, strerror(errno));
|
||
191 | } |
||
192 | #endif
|
||
193 | } |
||
194 | |||
195 | /* Set semaphore 1 back to zero. */
|
||
196 | |||
197 | sop[0].sem_num = SYSVSEM_SETVAL;
|
||
198 | sop[0].sem_op = -1; |
||
199 | sop[0].sem_flg = SEM_UNDO;
|
||
200 | while (semop(semid, sop, 1) == -1) { |
||
201 | if (errno != EINTR) {
|
||
202 | fprintf(stderr, "%s failed releasing SYSVSEM_SETVAL for key 0x%lx: %s\n", __FUNCTION__, key, strerror(errno));
|
||
203 | break;
|
||
204 | } |
||
205 | } |
||
206 | |||
207 | //sem_ptr = (sysvsem_sem *) emalloc(sizeof(sysvsem_sem));
|
||
208 | this->key = key;
|
||
209 | this->semid = semid;
|
||
210 | this->count = 0; |
||
211 | this->auto_release = auto_release;
|
||
212 | |||
213 | //this->id = (int)sem_ptr;
|
||
214 | |||
215 | //return sem_ptr;
|
||
216 | } |
||
217 | /* }}} */
|
||
218 | |||
219 | /* {{{ php_sysvsem_semop
|
||
220 | */
|
||
221 | int sysvsem::php_sysvsem_semop(int acquire) |
||
222 | { |
||
223 | struct sembuf sop;
|
||
224 | |||
225 | if (!acquire && this->count == 0) { |
||
226 | fprintf(stderr, "SysV semaphore 0x%x is not currently acquired\n", this->key); |
||
227 | return 0; |
||
228 | } |
||
229 | |||
230 | sop.sem_num = SYSVSEM_SEM; |
||
231 | sop.sem_op = acquire ? -1 : 1; |
||
232 | sop.sem_flg = SEM_UNDO; |
||
233 | |||
234 | while (semop(this->semid, &sop, 1) == -1) { |
||
235 | if (errno != EINTR) {
|
||
236 | fprintf(stderr, "%s failed to %s semaphore 0x%x: %s\n", __FUNCTION__, acquire ? "acquire" : "release", this->key, strerror(errno)); |
||
237 | return 0; |
||
238 | } |
||
239 | } |
||
240 | |||
241 | this->count -= acquire ? -1 : 1; |
||
242 | return 1; |
||
243 | } |
||
244 | /* }}} */
|
||
245 | |||
246 | /* {{{ proto bool sem_acquire(resource id)
|
||
247 | Acquires the semaphore with the given id, blocking if necessary */
|
||
248 | int sysvsem::sem_acquire()
|
||
249 | { |
||
250 | return this->php_sysvsem_semop(1); |
||
251 | } |
||
252 | /* }}} */
|
||
253 | |||
254 | /* {{{ proto bool sem_release(resource id)
|
||
255 | Releases the semaphore with the given id */
|
||
256 | int sysvsem::sem_release()
|
||
257 | { |
||
258 | return this->php_sysvsem_semop(0); |
||
259 | } |
||
260 | /* }}} */
|
||
261 | |||
262 | /* {{{ proto bool sem_remove(resource id)
|
||
263 | Removes semaphore from Unix systems */
|
||
264 | |||
265 | /*
|
||
266 | * contributed by Gavin Sherry gavin@linuxworld.com.au
|
||
267 | * Fri Mar 16 00:50:13 EST 2001
|
||
268 | */
|
||
269 | |||
270 | int sysvsem::sem_remove()
|
||
271 | { |
||
272 | #if HAVE_SEMUN
|
||
273 | union semun un;
|
||
274 | struct semid_ds buf;
|
||
275 | #endif
|
||
276 | |||
277 | #if HAVE_SEMUN
|
||
278 | un.buf = &buf; |
||
279 | if (semctl(this->semid, 0, IPC_STAT, un) < 0) { |
||
280 | #else
|
||
281 | if (semctl(this->semid, 0, IPC_STAT, NULL) < 0) { |
||
282 | #endif
|
||
283 | fprintf(stderr, "SysV semaphore 0x%x does not (any longer) exist\n", this->key); |
||
284 | return 0; |
||
285 | } |
||
286 | |||
287 | #if HAVE_SEMUN
|
||
288 | if (semctl(this->semid, 0, IPC_RMID, un) < 0) { |
||
289 | #else
|
||
290 | if (semctl(this->semid, 0, IPC_RMID, NULL) < 0) { |
||
291 | #endif
|
||
292 | fprintf(stderr, "%s failed for SysV sempphore 0x%x: %s\n", __FUNCTION__, this->key, strerror(errno)); |
||
293 | return 0; |
||
294 | } |
||
295 | |||
296 | /* let release_sysvsem_sem know we have removed
|
||
297 | * the semaphore to avoid issues with releasing.
|
||
298 | */
|
||
299 | |||
300 | this->count = -1; |
||
301 | return 1; |
||
302 | } |
||
303 | |||
304 | /* }}} */
|
||
305 | |||
306 | /*
|
||
307 | * Local variables:
|
||
308 | * tab-width: 4
|
||
309 | * c-basic-offset: 4
|
||
310 | * End:
|
||
311 | * vim600: sw=4 ts=4 fdm=marker
|
||
312 | * vim<600: sw=4 ts=4
|
||
313 | */ |