New PHP5 APC - version 3.0.19, using PHP5 5.2.0-8+etch11,
[php5-apc.git] / apc_sem.c
1 /*
2   +----------------------------------------------------------------------+
3   | APC                                                                  |
4   +----------------------------------------------------------------------+
5   | Copyright (c) 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: Daniel Cowgill <dcowgill@communityconnect.com>              |
16   +----------------------------------------------------------------------+
17
18    This software was contributed to PHP by Community Connect Inc. in 2002
19    and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1.
20    Future revisions and derivatives of this source code must acknowledge
21    Community Connect Inc. as the original contributor of this module by
22    leaving this note intact in the source code.
23
24    All other licensing and usage conditions are those of the PHP Group.
25
26  */
27
28 /* $Id: apc_sem.c,v 3.16.2.1 2008/05/11 18:57:00 rasmus Exp $ */
29
30 #include "apc_sem.h"
31 #include "apc.h"
32 #include "php.h"
33 #include <sys/types.h>
34 #include <sys/ipc.h>
35 #include <sys/sem.h>
36 #include <sys/stat.h>
37 #include <unistd.h>
38
39 #if HAVE_SEMUN
40 /* we have semun, no need to define */
41 #else
42 #undef HAVE_SEMUN
43 union semun {
44     int val;                  /* value for SETVAL */
45     struct semid_ds *buf;     /* buffer for IPC_STAT, IPC_SET */
46     unsigned short *array;    /* array for GETALL, SETALL */
47                               /* Linux specific part: */
48     struct seminfo *__buf;    /* buffer for IPC_INFO */
49 };
50 #define HAVE_SEMUN 1
51 #endif
52
53 #ifndef SEM_R
54 # define SEM_R 0444
55 #endif
56 #ifndef SEM_A
57 # define SEM_A 0222
58 #endif
59
60 /* always use SEM_UNDO, otherwise we risk deadlock */
61 #define USE_SEM_UNDO
62
63 #ifdef USE_SEM_UNDO
64 # define UNDO SEM_UNDO
65 #else
66 # define UNDO 0
67 #endif
68
69 int apc_sem_create(const char* pathname, int proj, int initval)
70 {
71     int semid;
72     int perms;
73     union semun arg;
74     key_t key;
75
76     perms = 0777;
77
78     key = IPC_PRIVATE;
79     if (pathname != NULL) {
80         if ((key = ftok(pathname, proj)) < 0) {
81             apc_eprint("apc_sem_create: ftok(%s,%d) failed:", pathname, proj);
82         }
83     }
84     
85     if ((semid = semget(key, 1, IPC_CREAT | IPC_EXCL | perms)) >= 0) {
86         /* sempahore created for the first time, initialize now */
87         arg.val = initval;
88         if (semctl(semid, 0, SETVAL, arg) < 0) {
89             apc_eprint("apc_sem_create: semctl(%d,...) failed:", semid);
90         }
91     }
92     else if (errno == EEXIST) {
93         /* sempahore already exists, don't initialize */
94         if ((semid = semget(key, 1, perms)) < 0) {
95             apc_eprint("apc_sem_create: semget(%u,...) failed:", key);
96         }
97         /* insert <sleazy way to avoid race condition> here */
98     }
99     else {
100         apc_eprint("apc_sem_create: semget(%u,...) failed:", key);
101     }
102
103     return semid;
104 }
105
106 void apc_sem_destroy(int semid)
107 {
108     /* we expect this call to fail often, so we do not check */
109     union semun arg;
110     semctl(semid, 0, IPC_RMID, arg);
111 }
112
113 void apc_sem_lock(int semid)
114 {
115     struct sembuf op;
116
117     op.sem_num = 0;
118     op.sem_op  = -1;
119     op.sem_flg = UNDO;
120
121     if (semop(semid, &op, 1) < 0) {
122         if (errno != EINTR) {
123             apc_eprint("apc_sem_lock: semop(%d) failed:", semid);
124         }
125     }
126 }
127
128 void apc_sem_unlock(int semid)
129 {
130     struct sembuf op;
131
132     op.sem_num = 0;
133     op.sem_op  = 1;
134     op.sem_flg = UNDO;
135
136     if (semop(semid, &op, 1) < 0) {
137         if (errno != EINTR) {
138             apc_eprint("apc_sem_unlock: semop(%d) failed:", semid);
139         }
140     }
141 }
142
143 void apc_sem_wait_for_zero(int semid)
144 {
145     struct sembuf op;
146
147     op.sem_num = 0;
148     op.sem_op  = 0;
149     op.sem_flg = UNDO;
150
151     if (semop(semid, &op, 1) < 0) {
152         if (errno != EINTR) {
153             apc_eprint("apc_sem_waitforzero: semop(%d) failed:", semid);
154         }
155     }
156 }
157
158 int apc_sem_get_value(int semid)
159 {
160     union semun arg;
161     unsigned short val[1];
162
163     arg.array = val;
164     if (semctl(semid, 0, GETALL, arg) < 0) {
165         apc_eprint("apc_sem_getvalue: semctl(%d,...) failed:", semid);
166     }
167     return val[0];
168 }
169
170 /*
171  * Local variables:
172  * tab-width: 4
173  * c-basic-offset: 4
174  * End:
175  * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker
176  * vim<600: expandtab sw=4 ts=4 sts=4
177  */