root / trunk / code / projects / colonet / server / vision / sysvsem.cpp @ 1428
History | View | Annotate | Download (8.92 KB)
1 |
/*
|
---|---|
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 |
*/
|