process_shared 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. data/COPYING +19 -0
  2. data/ChangeLog +0 -0
  3. data/README.rdoc +69 -0
  4. data/ext/libpsem/bsem.c +188 -0
  5. data/ext/libpsem/bsem.h +32 -0
  6. data/ext/libpsem/constants.c +22 -0
  7. data/ext/libpsem/constants.h +18 -0
  8. data/ext/libpsem/extconf.rb +36 -0
  9. data/ext/libpsem/mempcpy.c +7 -0
  10. data/ext/libpsem/mempcpy.h +13 -0
  11. data/ext/libpsem/mutex.c +15 -0
  12. data/ext/libpsem/mutex.h +14 -0
  13. data/ext/libpsem/psem.c +15 -0
  14. data/ext/libpsem/psem.h +43 -0
  15. data/ext/libpsem/psem_error.c +46 -0
  16. data/ext/libpsem/psem_error.h +11 -0
  17. data/ext/libpsem/psem_posix.c +130 -0
  18. data/ext/libpsem/psem_posix.h +10 -0
  19. data/ext/pthread_sync_helper/extconf.rb +9 -0
  20. data/ext/pthread_sync_helper/pthread_sync_helper.c +43 -0
  21. data/ext/semaphore.c +623 -0
  22. data/lib/process_shared.rb +6 -0
  23. data/lib/process_shared/abstract_semaphore.rb +50 -0
  24. data/lib/process_shared/bounded_semaphore.rb +43 -0
  25. data/lib/process_shared/condition_variable.rb +27 -0
  26. data/lib/process_shared/libc.rb +36 -0
  27. data/lib/process_shared/libpsem.bundle +0 -0
  28. data/lib/process_shared/libpsem.so +0 -0
  29. data/lib/process_shared/mutex.rb +103 -0
  30. data/lib/process_shared/posix_call.rb +29 -0
  31. data/lib/process_shared/process_error.rb +3 -0
  32. data/lib/process_shared/psem.rb +109 -0
  33. data/lib/process_shared/rt.rb +21 -0
  34. data/lib/process_shared/semaphore.rb +60 -0
  35. data/lib/process_shared/shared_memory.rb +45 -0
  36. data/lib/process_shared/thread.rb +30 -0
  37. data/lib/process_shared/with_self.rb +20 -0
  38. data/lib/scratch.rb +300 -0
  39. data/spec/process_shared/bounded_semaphore_spec.rb +48 -0
  40. data/spec/process_shared/libc_spec.rb +9 -0
  41. data/spec/process_shared/mutex_spec.rb +74 -0
  42. data/spec/process_shared/psem_spec.rb +136 -0
  43. data/spec/process_shared/semaphore_spec.rb +76 -0
  44. data/spec/process_shared/shared_memory_spec.rb +36 -0
  45. data/spec/spec_helper.rb +35 -0
  46. metadata +139 -0
@@ -0,0 +1,15 @@
1
+ #include "psem.h"
2
+
3
+ int OK = 0;
4
+ int ERROR = -1;
5
+
6
+ int E_SOURCE_SYSTEM = 1;
7
+ int E_SOURCE_PSEM = 2;
8
+
9
+ int E_NAME_TOO_LONG = 1;
10
+
11
+ #ifdef HAVE_SEM_OPEN
12
+ #include "psem_posix.c"
13
+ #endif
14
+
15
+ size_t sizeof_psem_t = sizeof (psem_t);
@@ -0,0 +1,43 @@
1
+ #ifndef __PSEM_H__
2
+ #define __PSEM_H__
3
+
4
+ /**
5
+ * Portable semaphore interface focusing on cross-process use.
6
+ */
7
+
8
+ #ifdef HAVE_SEM_OPEN
9
+ #include "psem_posix.h"
10
+ #endif
11
+
12
+ #include "psem_error.h"
13
+
14
+ typedef struct psem psem_t;
15
+
16
+ extern size_t sizeof_psem_t;
17
+
18
+ extern int OK;
19
+ extern int ERROR;
20
+
21
+ extern int E_SOURCE_SYSTEM;
22
+ extern int E_SOURCE_PSEM;
23
+
24
+ extern int E_NAME_TOO_LONG;
25
+
26
+ int psem_errno();
27
+
28
+ psem_t * psem_alloc();
29
+ void psem_free(psem_t *);
30
+
31
+ int psem_open(psem_t *, const char *, unsigned int, error_t **);
32
+ int psem_close(psem_t *, error_t **);
33
+ int psem_unlink(const char *, error_t **);
34
+
35
+ int psem_post(psem_t *, error_t **);
36
+
37
+ int psem_wait(psem_t *, error_t **);
38
+ int psem_trywait(psem_t *, error_t **);
39
+ int psem_timedwait(psem_t *, float, error_t **);
40
+
41
+ int psem_getvalue(psem_t *, int *, error_t **);
42
+
43
+ #endif /* __PSEM_H__ */
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Similar to GError from GLib.
3
+ */
4
+
5
+ #include <stdlib.h> /* malloc, free */
6
+
7
+ #include "psem_error.h"
8
+
9
+ struct error {
10
+ int error_source;
11
+ int error_number;
12
+ };
13
+
14
+ error_t *
15
+ error_alloc()
16
+ {
17
+ return (error_t *) malloc(sizeof (error_t));
18
+ }
19
+
20
+ void
21
+ error_free(error_t *err)
22
+ {
23
+ free(err);
24
+ }
25
+
26
+ void
27
+ error_set(error_t *err, int source, int value)
28
+ {
29
+ err->error_source = source;
30
+ err->error_number = value;
31
+ }
32
+
33
+ void
34
+ error_new(error_t **err, int source, int value)
35
+ {
36
+ if (err != NULL) {
37
+ if (*err == NULL) {
38
+ *err = error_alloc();
39
+ error_set(*err, source, value);
40
+ } else {
41
+ /* tried to create a new error atop an existing error... */
42
+ }
43
+ } else {
44
+ /* error is being ignored by caller */
45
+ }
46
+ }
@@ -0,0 +1,11 @@
1
+ #ifndef __PSEM_ERROR_H__
2
+ #define __PSEM_ERROR_H__
3
+
4
+ typedef struct error error_t;
5
+
6
+ error_t * error_alloc();
7
+ void error_free(error_t *);
8
+
9
+ void error_set(error_t *, int, int);
10
+
11
+ #endif /* __PSEM_ERROR_H__ */
@@ -0,0 +1,130 @@
1
+ /*
2
+ * A type which wraps a semaphore
3
+ *
4
+ * semaphore.c
5
+ *
6
+ * Copyright (c) 2006-2008, R Oudkerk
7
+ *
8
+ * All rights reserved.
9
+ *
10
+ * Redistribution and use in source and binary forms, with or without
11
+ * modification, are permitted provided that the following conditions
12
+ * are met:
13
+ *
14
+ * 1. Redistributions of source code must retain the above copyright
15
+ * notice, this list of conditions and the following disclaimer.
16
+ *
17
+ * 2. Redistributions in binary form must reproduce the above
18
+ * copyright notice, this list of conditions and the following
19
+ * disclaimer in the documentation and/or other materials provided
20
+ * with the distribution.
21
+ *
22
+ * 3. Neither the name of author nor the names of any contributors
23
+ * may be used to endorse or promote products derived from this
24
+ * software without specific prior written permission.
25
+ *
26
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS"
27
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
29
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR
30
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
32
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
33
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
34
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
36
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37
+ * POSSIBILITY OF SUCH DAMAGE.
38
+ */
39
+
40
+ /*
41
+ * Modifications Copyright (c) 2011, Patrick Mahoney
42
+ */
43
+
44
+ #include <errno.h>
45
+ #include <fcntl.h> /* For O_* constants */
46
+ #include <sys/stat.h> /* For mode constants */
47
+ #include <semaphore.h>
48
+ #include <stdlib.h> /* malloc, free */
49
+ #include <math.h> /* floorf */
50
+ #include <time.h> /* timespec */
51
+
52
+ #include "psem.h"
53
+ #include "psem_posix.h"
54
+
55
+ psem_t *
56
+ psem_alloc(void) {
57
+ return (psem_t *) malloc(sizeof(psem_t));
58
+ }
59
+
60
+ void
61
+ psem_free(psem_t *psem) {
62
+ free(psem);
63
+ }
64
+
65
+ #define errcheck_val(expr, errval, err) \
66
+ do { \
67
+ if ((expr) == (errval)) { \
68
+ error_new((err), E_SOURCE_SYSTEM, errno); \
69
+ return ERROR; \
70
+ } \
71
+ return OK; \
72
+ } while (0)
73
+
74
+ #define errcheck(expr, err) errcheck_val((expr), -1, (err))
75
+
76
+ int
77
+ psem_open(psem_t *psem, const char *name, unsigned int value, error_t **err)
78
+ {
79
+ errcheck_val(psem->sem = sem_open(name, O_CREAT | O_EXCL, 0600, value),
80
+ SEM_FAILED,
81
+ err);
82
+ }
83
+
84
+ int
85
+ psem_close(psem_t *psem, error_t **err)
86
+ {
87
+ errcheck(sem_close(psem->sem), err);
88
+ }
89
+
90
+ int
91
+ psem_unlink(const char *name, error_t **err)
92
+ {
93
+ errcheck(sem_unlink(name), err);
94
+ }
95
+
96
+ int
97
+ psem_post(psem_t *psem, error_t **err)
98
+ {
99
+ errcheck(sem_post(psem->sem), err);
100
+ }
101
+
102
+ int
103
+ psem_wait(psem_t *psem, error_t **err)
104
+ {
105
+ errcheck(sem_wait(psem->sem), err);
106
+ }
107
+
108
+ int
109
+ psem_trywait(psem_t *psem, error_t **err)
110
+ {
111
+ errcheck(sem_trywait(psem->sem), err);
112
+ }
113
+
114
+ int
115
+ psem_timedwait(psem_t *psem, float timeout_s, error_t **err)
116
+ {
117
+ struct timespec abs_timeout;
118
+
119
+ abs_timeout.tv_sec = floorf(timeout_s);
120
+ abs_timeout.tv_nsec =
121
+ floorf((timeout_s - abs_timeout.tv_sec) * (1000 * 1000 * 1000));
122
+
123
+ errcheck(sem_timedwait(psem->sem, &abs_timeout), err);
124
+ }
125
+
126
+ int
127
+ psem_getvalue(psem_t *psem, int *sval, error_t **err)
128
+ {
129
+ errcheck(sem_getvalue(psem->sem, sval), err);
130
+ }
@@ -0,0 +1,10 @@
1
+ #ifndef __PSEM_POSIX_H__
2
+ #define __PSEM_POSIX_H__
3
+
4
+ #include <semaphore.h>
5
+
6
+ struct psem {
7
+ sem_t *sem;
8
+ };
9
+
10
+ #endif /* __PSEM_POSIX_H__ */
@@ -0,0 +1,9 @@
1
+ require 'mkmf'
2
+
3
+ #have_func("pthread_mutex_init", "pthread.h")
4
+ #have_func("pthread_cond_init", "pthread.h")
5
+ #have_func("pthread_mutex_trylock", "pthread.h")
6
+
7
+ have_library("pthread", "pthread_mutex_init")
8
+
9
+ create_makefile("pthread_sync_helper")
@@ -0,0 +1,43 @@
1
+ #include <pthread.h>
2
+ #include <sys/mman.h> /* PROT_*, MAP_* */
3
+ #include <fcntl.h> /* O_* */
4
+
5
+ /* Declarations. These are split this way to avoid compiler warnings. */
6
+
7
+ extern size_t sizeof_pthread_mutex_t;
8
+ extern size_t sizeof_pthread_mutexattr_t;
9
+
10
+ extern int pthread_process_shared;
11
+
12
+ extern int o_rdwr;
13
+ extern int o_creat;
14
+
15
+ extern int prot_read;
16
+ extern int prot_write;
17
+ extern int prot_exec;
18
+ extern int prot_none;
19
+
20
+ extern void * map_failed;
21
+
22
+ extern int map_shared;
23
+ extern int map_private;
24
+
25
+ /* Definitions. These are split from declrations to avoid compiler warnings. */
26
+
27
+ size_t sizeof_pthread_mutex_t = sizeof (pthread_mutex_t);
28
+ size_t sizeof_pthread_mutexattr_t = sizeof (pthread_mutexattr_t);
29
+
30
+ int pthread_process_shared = PTHREAD_PROCESS_SHARED;
31
+
32
+ int o_rdwr = O_RDWR;
33
+ int o_creat = O_CREAT;
34
+
35
+ int prot_read = PROT_READ;
36
+ int prot_write = PROT_WRITE;
37
+ int prot_exec = PROT_EXEC;
38
+ int prot_none = PROT_NONE;
39
+
40
+ void * map_failed = MAP_FAILED;
41
+
42
+ int map_shared = MAP_SHARED;
43
+ int map_private = MAP_PRIVATE;
@@ -0,0 +1,623 @@
1
+ /*
2
+ * A type which wraps a semaphore
3
+ *
4
+ * semaphore.c
5
+ *
6
+ * Copyright (c) 2006-2008, R Oudkerk
7
+ *
8
+ * All rights reserved.
9
+ *
10
+ * Redistribution and use in source and binary forms, with or without
11
+ * modification, are permitted provided that the following conditions
12
+ * are met:
13
+ *
14
+ * 1. Redistributions of source code must retain the above copyright
15
+ * notice, this list of conditions and the following disclaimer.
16
+ *
17
+ * 2. Redistributions in binary form must reproduce the above
18
+ * copyright notice, this list of conditions and the following
19
+ * disclaimer in the documentation and/or other materials provided
20
+ * with the distribution.
21
+ *
22
+ * 3. Neither the name of author nor the names of any contributors
23
+ * may be used to endorse or promote products derived from this
24
+ * software without specific prior written permission.
25
+ *
26
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS"
27
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
29
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR
30
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
32
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
33
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
34
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
36
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37
+ * POSSIBILITY OF SUCH DAMAGE.
38
+ */
39
+
40
+ /*
41
+ * Modifications Copyright (c) 2011, Patrick Mahoney
42
+ */
43
+
44
+ #include "processing.h"
45
+
46
+ enum {
47
+ RECURSIVE_MUTEX,
48
+ SEMAPHORE,
49
+ BOUNDED_SEMAPHORE
50
+ };
51
+
52
+ typedef struct {
53
+ PyObject_HEAD
54
+ SEM_HANDLE handle;
55
+ long last_tid;
56
+ int count;
57
+ int maxvalue;
58
+ int kind;
59
+ } SemLock;
60
+
61
+ #define ISMINE(o) (o->count > 0 && PyThread_get_thread_ident() == o->last_tid)
62
+
63
+
64
+ #ifdef MS_WINDOWS
65
+
66
+ /*
67
+ * Windows definitions
68
+ */
69
+
70
+ static SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
71
+
72
+ #define SEM_FAILED NULL
73
+
74
+ #define SEM_CLEAR_ERROR() SetLastError(0)
75
+ #define SEM_GET_LAST_ERROR() GetLastError()
76
+ #define SEM_CREATE(name, val, max) CreateSemaphore(&sa, val, max, NULL)
77
+ #define SEM_CLOSE(sem) (CloseHandle(sem) ? 0 : -1)
78
+ #define SEM_GETVALUE(sem, pval) _SemLock_GetSemaphoreValue(sem, pval)
79
+ #define SEM_UNLINK(name) 0
80
+
81
+ static int
82
+ _SemLock_GetSemaphoreValue(HANDLE handle, long *value)
83
+ {
84
+ long previous;
85
+
86
+ switch (WaitForSingleObject(handle, 0)) {
87
+ case WAIT_OBJECT_0:
88
+ if (!ReleaseSemaphore(handle, 1, &previous))
89
+ return STANDARD_ERROR;
90
+ *value = previous + 1;
91
+ return 0;
92
+ case WAIT_TIMEOUT:
93
+ *value = 0;
94
+ return 0;
95
+ default:
96
+ return STANDARD_ERROR;
97
+ }
98
+ }
99
+
100
+ static PyObject *
101
+ SemLock_acquire(SemLock *self, PyObject *args, PyObject *kwds)
102
+ {
103
+ int blocking = 1;
104
+ double timeout;
105
+ PyObject *timeout_obj = Py_None;
106
+ DWORD res, dwTimeout;
107
+
108
+ static char *kwlist[] = {"block", "timeout", NULL};
109
+
110
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|iO", kwlist,
111
+ &blocking, &timeout_obj))
112
+ return NULL;
113
+
114
+ if (self->kind == RECURSIVE_MUTEX && ISMINE(self)) {
115
+ ++self->count;
116
+ Py_RETURN_TRUE;
117
+ }
118
+
119
+ /* work out timeout */
120
+ if (!blocking) {
121
+ dwTimeout = 0;
122
+ } else if (timeout_obj == Py_None) {
123
+ dwTimeout = INFINITE;
124
+ } else {
125
+ timeout = PyFloat_AsDouble(timeout_obj);
126
+ if (PyErr_Occurred())
127
+ return NULL;
128
+ timeout *= 1000.0; /* convert to millisecs */
129
+ if (timeout < 0.0) {
130
+ timeout = 0.0;
131
+ } else if (timeout >= ((double)INFINITE - 0.5)) {
132
+ PyErr_SetString(PyExc_OverflowError, "timeout is too large");
133
+ return NULL;
134
+ }
135
+ dwTimeout = (DWORD)(timeout + 0.5);
136
+ }
137
+
138
+ /* do the wait */
139
+ if (dwTimeout == 0) {
140
+ res = WaitForSingleObject(self->handle, 0);
141
+ } else if (main_thread == GetCurrentThreadId()) {
142
+ res = WaitForSingleObject(self->handle, 0);
143
+ if (res == WAIT_TIMEOUT) {
144
+ HANDLE handles[2] = {self->handle, hInterruptEvent};
145
+ ResetEvent(hInterruptEvent);
146
+ Py_BEGIN_ALLOW_THREADS
147
+ res = WaitForMultipleObjects(2, handles, FALSE, dwTimeout);
148
+ Py_END_ALLOW_THREADS
149
+ }
150
+ } else {
151
+ Py_BEGIN_ALLOW_THREADS
152
+ res = WaitForSingleObject(self->handle, dwTimeout);
153
+ Py_END_ALLOW_THREADS
154
+ }
155
+
156
+ /* handle result */
157
+ switch (res) {
158
+ case WAIT_TIMEOUT:
159
+ Py_RETURN_FALSE;
160
+ case WAIT_OBJECT_0:
161
+ self->last_tid = GetCurrentThreadId();
162
+ ++self->count;
163
+ Py_RETURN_TRUE;
164
+ case (WAIT_OBJECT_0 + 1): /* we got SIGINT; do like in timemodule.c */
165
+ Sleep(1);
166
+ errno = EINTR;
167
+ PyErr_SetFromErrno(PyExc_OSError);
168
+ return NULL;
169
+ case WAIT_FAILED:
170
+ return PyErr_SetFromWindowsErr(0);
171
+ default:
172
+ PyErr_SetString(PyExc_RuntimeError, "WaitForSingleObject() or "
173
+ "WaitForMultipleObjects() gave unrecognized value");
174
+ return NULL;
175
+ }
176
+ }
177
+
178
+ static PyObject *
179
+ SemLock_release(SemLock *self, PyObject *args)
180
+ {
181
+ if (self->kind == RECURSIVE_MUTEX) {
182
+ if (!ISMINE(self)) {
183
+ PyErr_SetString(PyExc_AssertionError, "attempt to release "
184
+ "recursive lock not owned by thread");
185
+ return NULL;
186
+ }
187
+ if (self->count > 1) {
188
+ --self->count;
189
+ Py_RETURN_NONE;
190
+ }
191
+ assert(self->count == 1);
192
+ }
193
+
194
+ if (!ReleaseSemaphore(self->handle, 1, NULL)) {
195
+ if (GetLastError() == ERROR_TOO_MANY_POSTS) {
196
+ PyErr_SetString(PyExc_ValueError,
197
+ "semaphore or lock released too many times");
198
+ return NULL;
199
+ } else {
200
+ return PyErr_SetFromWindowsErr(0);
201
+ }
202
+ }
203
+
204
+ --self->count;
205
+ Py_RETURN_NONE;
206
+ }
207
+
208
+ #else /* !MS_WINDOWS */
209
+
210
+ /*
211
+ * Unix definitions
212
+ */
213
+
214
+ #define SEM_CLEAR_ERROR()
215
+ #define SEM_GET_LAST_ERROR() 0
216
+ #define SEM_CREATE(name, val, max) sem_open(name, O_CREAT | O_EXCL, 0600, val)
217
+ #define SEM_CLOSE(sem) sem_close(sem)
218
+ #define SEM_GETVALUE(sem, pval) sem_getvalue(sem, pval)
219
+ #define SEM_UNLINK(name) sem_unlink(name)
220
+
221
+ #if HAVE_BROKEN_SEM_UNLINK
222
+ # define sem_unlink(name) 0
223
+ #endif
224
+
225
+ #if !HAVE_SEM_TIMEDWAIT
226
+ # define sem_timedwait(sem,deadline) sem_timedwait_save(sem,deadline,_save)
227
+
228
+ int
229
+ sem_timedwait_save(sem_t *sem, struct timespec *deadline, PyThreadState *_save)
230
+ {
231
+ int res;
232
+ unsigned long delay, difference;
233
+ struct timeval now, tvdeadline, tvdelay;
234
+
235
+ errno = 0;
236
+ tvdeadline.tv_sec = deadline->tv_sec;
237
+ tvdeadline.tv_usec = deadline->tv_nsec / 1000;
238
+
239
+ for (delay = 0 ; ; delay += 1000) {
240
+ /* poll */
241
+ if (sem_trywait(sem) == 0)
242
+ return 0;
243
+ else if (errno != EAGAIN)
244
+ return STANDARD_ERROR;
245
+
246
+ /* get current time */
247
+ if (gettimeofday(&now, NULL) < 0)
248
+ return STANDARD_ERROR;
249
+
250
+ /* check for timeout */
251
+ if (tvdeadline.tv_sec < now.tv_sec ||
252
+ (tvdeadline.tv_sec == now.tv_sec &&
253
+ tvdeadline.tv_usec <= now.tv_usec)) {
254
+ errno = ETIMEDOUT;
255
+ return STANDARD_ERROR;
256
+ }
257
+
258
+ /* calculate how much time is left */
259
+ difference = (tvdeadline.tv_sec - now.tv_sec) * 1000000 +
260
+ (tvdeadline.tv_usec - now.tv_usec);
261
+
262
+ /* check delay not too long -- maximum is 20 msecs */
263
+ if (delay > 20000)
264
+ delay = 20000;
265
+ if (delay > difference)
266
+ delay = difference;
267
+
268
+ /* sleep */
269
+ tvdelay.tv_sec = delay / 1000000;
270
+ tvdelay.tv_usec = delay % 1000000;
271
+ if (select(0, NULL, NULL, NULL, &tvdelay) < 0)
272
+ return STANDARD_ERROR;
273
+
274
+ /* check for signals */
275
+ Py_BLOCK_THREADS
276
+ res = PyErr_CheckSignals();
277
+ Py_UNBLOCK_THREADS
278
+
279
+ if (res) {
280
+ errno = EINTR;
281
+ return EXCEPTION_HAS_BEEN_SET;
282
+ }
283
+ }
284
+ }
285
+
286
+ #endif /* !HAVE_SEM_TIMEDWAIT */
287
+
288
+ static PyObject *
289
+ SemLock_acquire(SemLock *self, PyObject *args, PyObject *kwds)
290
+ {
291
+ int blocking = 1, res;
292
+ double timeout;
293
+ PyObject *timeout_obj = Py_None;
294
+ struct timespec deadline = {0};
295
+ struct timeval now;
296
+ long sec, nsec;
297
+
298
+ static char *kwlist[] = {"block", "timeout", NULL};
299
+
300
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|iO", kwlist,
301
+ &blocking, &timeout_obj))
302
+ return NULL;
303
+
304
+ if (self->kind == RECURSIVE_MUTEX && ISMINE(self)) {
305
+ ++self->count;
306
+ Py_RETURN_TRUE;
307
+ }
308
+
309
+ if (timeout_obj != Py_None) {
310
+ timeout = PyFloat_AsDouble(timeout_obj);
311
+ if (PyErr_Occurred())
312
+ return NULL;
313
+ if (timeout < 0.0)
314
+ timeout = 0.0;
315
+
316
+ if (gettimeofday(&now, NULL) < 0) {
317
+ PyErr_SetFromErrno(PyExc_OSError);
318
+ return NULL;
319
+ }
320
+ sec = (long) timeout;
321
+ nsec = (long) (1e9 * (timeout - sec) + 0.5);
322
+ deadline.tv_sec = now.tv_sec + sec;
323
+ deadline.tv_nsec = now.tv_usec * 1000 + nsec;
324
+ deadline.tv_sec += (deadline.tv_nsec / 1000000000);
325
+ deadline.tv_nsec %= 1000000000;
326
+ }
327
+
328
+ do {
329
+ Py_BEGIN_ALLOW_THREADS
330
+ if (blocking && timeout_obj == Py_None)
331
+ res = sem_wait(self->handle);
332
+ else if (!blocking)
333
+ res = sem_trywait(self->handle);
334
+ else
335
+ res = sem_timedwait(self->handle, &deadline);
336
+ Py_END_ALLOW_THREADS
337
+ if (res == EXCEPTION_HAS_BEEN_SET)
338
+ break;
339
+ } while (res < 0 && errno == EINTR && !PyErr_CheckSignals());
340
+
341
+ if (res < 0) {
342
+ if (errno == EAGAIN || errno == ETIMEDOUT)
343
+ Py_RETURN_FALSE;
344
+ else if (errno == EINTR)
345
+ return NULL;
346
+ else
347
+ return PyErr_SetFromErrno(PyExc_OSError);
348
+ }
349
+
350
+ ++self->count;
351
+ self->last_tid = PyThread_get_thread_ident();
352
+
353
+ Py_RETURN_TRUE;
354
+ }
355
+
356
+ static PyObject *
357
+ SemLock_release(SemLock *self, PyObject *args)
358
+ {
359
+ switch (self->kind) {
360
+ case RECURSIVE_MUTEX:
361
+ if (!ISMINE(self)) {
362
+ PyErr_SetString(PyExc_AssertionError, "attempt to release "
363
+ "recursive lock not owned by thread");
364
+ return NULL;
365
+ }
366
+ if (self->count > 1) {
367
+ --self->count;
368
+ Py_RETURN_NONE;
369
+ }
370
+ assert(self->count == 1);
371
+ break;
372
+ #if HAVE_BROKEN_SEM_GETVALUE
373
+ case BOUNDED_SEMAPHORE:
374
+ /* We will only check properly the Lock case (where maxvalue == 1) */
375
+ if (self->maxvalue == 1) {
376
+ /* make sure that already locked */
377
+ if (sem_trywait(self->handle) < 0) {
378
+ if (errno != EAGAIN)
379
+ return PyErr_SetFromErrno(PyExc_OSError);
380
+ /* it is already locked as expected */
381
+ } else {
382
+ /* it was not locked -- so undo wait and raise error */
383
+ if (sem_post(self->handle) < 0)
384
+ return PyErr_SetFromErrno(PyExc_OSError);
385
+ PyErr_SetString(PyExc_ValueError,
386
+ "semaphore or lock released too many times");
387
+ return NULL;
388
+ }
389
+ }
390
+ #else
391
+ case BOUNDED_SEMAPHORE:
392
+ {
393
+ int sval;
394
+
395
+ /* This check is not an absolute guarantee that the semaphore
396
+ does not rise above maxvalue. */
397
+ if (sem_getvalue(self->handle, &sval) < 0) {
398
+ return PyErr_SetFromErrno(PyExc_OSError);
399
+ } else if (sval >= self->maxvalue) {
400
+ PyErr_SetString(PyExc_ValueError,
401
+ "semaphore or lock released too many times");
402
+ return NULL;
403
+ }
404
+ }
405
+ #endif
406
+ }
407
+
408
+ if (sem_post(self->handle) < 0)
409
+ return PyErr_SetFromErrno(PyExc_OSError);
410
+
411
+ --self->count;
412
+ Py_RETURN_NONE;
413
+ }
414
+
415
+ #endif /* !MS_WINDOWS */
416
+
417
+ /*
418
+ * All platforms
419
+ */
420
+
421
+ static PyObject *
422
+ _SemLock_create(PyTypeObject *type, SEM_HANDLE handle, int kind, int maxvalue)
423
+ {
424
+ SemLock *self;
425
+
426
+ self = (SemLock*)type->tp_alloc(type, 0);
427
+ if (!self)
428
+ return NULL;
429
+ self->handle = handle;
430
+ self->kind = kind;
431
+ self->count = 0;
432
+ self->last_tid = 0;
433
+ self->maxvalue = maxvalue;
434
+ return (PyObject*)self;
435
+ }
436
+
437
+ static PyObject *
438
+ SemLock_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
439
+ {
440
+ char buffer[256];
441
+ SEM_HANDLE handle = SEM_FAILED;
442
+ int kind, maxvalue, value;
443
+ PyObject *result;
444
+ static char *kwlist[] = {"kind", "value", NULL};
445
+ static int counter = 0;
446
+
447
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "ii", kwlist, &kind, &value))
448
+ return NULL;
449
+
450
+ if (kind < RECURSIVE_MUTEX || kind > BOUNDED_SEMAPHORE) {
451
+ PyErr_SetString(PyExc_ValueError, "unrecongnized blocker type");
452
+ return NULL;
453
+ }
454
+
455
+ PyOS_snprintf(buffer, sizeof(buffer), "/pr%d-%d", getpid(), counter++);
456
+
457
+ if (kind == BOUNDED_SEMAPHORE)
458
+ maxvalue = value;
459
+ else if (kind == RECURSIVE_MUTEX)
460
+ maxvalue = 1;
461
+ else
462
+ maxvalue = INT_MAX;
463
+
464
+ SEM_CLEAR_ERROR();
465
+ handle = SEM_CREATE(buffer, value, maxvalue);
466
+ /* On Windows we should fail if GetLastError() == ERROR_ALREADY_EXISTS */
467
+ if (handle == SEM_FAILED || SEM_GET_LAST_ERROR() != 0)
468
+ goto failure;
469
+
470
+ if (SEM_UNLINK(buffer) < 0)
471
+ goto failure;
472
+
473
+ result = _SemLock_create(type, handle, kind, maxvalue);
474
+ if (!result)
475
+ goto failure;
476
+
477
+ return result;
478
+
479
+ failure:
480
+ if (handle != SEM_FAILED)
481
+ SEM_CLOSE(handle);
482
+ SetException(NULL, STANDARD_ERROR);
483
+ return NULL;
484
+ }
485
+
486
+ static PyObject *
487
+ SemLock_rebuild(PyTypeObject *type, PyObject *args)
488
+ {
489
+ SEM_HANDLE handle;
490
+ int kind, maxvalue;
491
+
492
+ if (!PyArg_ParseTuple(args, F_SEM_HANDLE "ii", &handle, &kind, &maxvalue))
493
+ return NULL;
494
+
495
+ return _SemLock_create(type, handle, kind, maxvalue);
496
+ }
497
+
498
+ static void
499
+ SemLock_dealloc(SemLock* self)
500
+ {
501
+ if (self->handle != SEM_FAILED)
502
+ SEM_CLOSE(self->handle);
503
+ self->ob_type->tp_free((PyObject*)self);
504
+ }
505
+
506
+ static PyObject *
507
+ SemLock_count(SemLock *self)
508
+ {
509
+ return PyInt_FromLong((long)self->count);
510
+ }
511
+
512
+ static PyObject *
513
+ SemLock_ismine(SemLock *self)
514
+ {
515
+ /* only makes sense for a lock */
516
+ return PyBool_FromLong(ISMINE(self));
517
+ }
518
+
519
+ static PyObject *
520
+ SemLock_getvalue(SemLock *self)
521
+ {
522
+ #if HAVE_BROKEN_SEM_GETVALUE
523
+ PyErr_SetNone(PyExc_NotImplementedError);
524
+ return NULL;
525
+ #else
526
+ int sval;
527
+ if (SEM_GETVALUE(self->handle, &sval) < 0)
528
+ SetException(NULL, STANDARD_ERROR);
529
+ return PyInt_FromLong((long)sval);
530
+ #endif
531
+ }
532
+
533
+ static PyObject *
534
+ SemLock_afterfork(SemLock *self)
535
+ {
536
+ self->count = 0;
537
+ Py_RETURN_NONE;
538
+ }
539
+
540
+ /*
541
+ * Semaphore methods
542
+ */
543
+
544
+ static PyMethodDef SemLock_methods[] = {
545
+ {"acquire", (PyCFunction)SemLock_acquire, METH_KEYWORDS,
546
+ "acquire the semaphore/lock"},
547
+ {"release", (PyCFunction)SemLock_release, METH_NOARGS,
548
+ "release the semaphore/lock"},
549
+ {"__enter__", (PyCFunction)SemLock_acquire, METH_KEYWORDS,
550
+ "enter the semaphore/lock"},
551
+ {"__exit__", (PyCFunction)SemLock_release, METH_VARARGS,
552
+ "exit the semaphore/lock"},
553
+ {"_count", (PyCFunction)SemLock_count, METH_NOARGS,
554
+ "number of `acquire()`s minus number of `release()`s for this process"},
555
+ {"_isMine", (PyCFunction)SemLock_ismine, METH_NOARGS,
556
+ "whether the lock is owned by this thread"},
557
+ {"_getValue", (PyCFunction)SemLock_getvalue, METH_NOARGS,
558
+ "get the value of the semaphore"},
559
+ {"_rebuild", (PyCFunction)SemLock_rebuild, METH_VARARGS | METH_CLASS,
560
+ ""},
561
+ {"_afterFork", (PyCFunction)SemLock_afterfork, METH_NOARGS,
562
+ "rezero the net acquisition count after fork()"},
563
+ {NULL}
564
+ };
565
+
566
+ /*
567
+ * Member table
568
+ */
569
+
570
+ static PyMemberDef SemLock_members[] = {
571
+ {"handle", T_SEM_HANDLE, offsetof(SemLock, handle), READONLY, ""},
572
+ {"kind", T_INT, offsetof(SemLock, kind), READONLY, ""},
573
+ {"maxvalue", T_INT, offsetof(SemLock, maxvalue), READONLY, ""},
574
+ {NULL}
575
+ };
576
+
577
+ /*
578
+ * Semaphore type
579
+ */
580
+
581
+ PyTypeObject SemLockType = {
582
+ PyObject_HEAD_INIT(NULL)
583
+ 0, /* ob_size */
584
+ "_processing.SemLock", /* tp_name */
585
+ sizeof(SemLock), /* tp_basicsize */
586
+ 0, /* tp_itemsize */
587
+ (destructor)SemLock_dealloc,
588
+ /* tp_dealloc */
589
+ 0, /* tp_print */
590
+ 0, /* tp_getattr */
591
+ 0, /* tp_setattr */
592
+ 0, /* tp_compare */
593
+ 0, /* tp_repr */
594
+ 0, /* tp_as_number */
595
+ 0, /* tp_as_sequence */
596
+ 0, /* tp_as_mapping */
597
+ 0, /* tp_hash */
598
+ 0, /* tp_call */
599
+ 0, /* tp_str */
600
+ 0, /* tp_getattro */
601
+ 0, /* tp_setattro */
602
+ 0, /* tp_as_buffer */
603
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
604
+ /* tp_flags */
605
+ "Semaphore/Mutex type", /* tp_doc */
606
+ 0, /* tp_traverse */
607
+ 0, /* tp_clear */
608
+ 0, /* tp_richcompare */
609
+ 0, /* tp_weaklistoffset */
610
+ 0, /* tp_iter */
611
+ 0, /* tp_iternext */
612
+ SemLock_methods, /* tp_methods */
613
+ SemLock_members, /* tp_members */
614
+ 0, /* tp_getset */
615
+ 0, /* tp_base */
616
+ 0, /* tp_dict */
617
+ 0, /* tp_descr_get */
618
+ 0, /* tp_descr_set */
619
+ 0, /* tp_dictoffset */
620
+ 0, /* tp_init */
621
+ 0, /* tp_alloc */
622
+ (newfunc)SemLock_new, /* tp_new */
623
+ };