process_shared 0.2.0 → 0.2.1a

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 159a6ddc012e5c9ae969b505375b65c4ce28211d
4
- data.tar.gz: d1ecb4700906ad8b9534fd3535f4e4e33e34bc52
3
+ metadata.gz: 42192608a911df5503886fa0f851a7cd23f13348
4
+ data.tar.gz: 1f8db3382f895196e5bb7edb9818d1a414186740
5
5
  SHA512:
6
- metadata.gz: 1ab8b394e065e57c42bfb403a7f37262651fd3c8a81ee98c2fd7d7bec812afb9e305ab598b43ee3321a09407bfd901da8397abc4baa3e24bd64d20ef3b5ca3ef
7
- data.tar.gz: 266a1ed392b960097f638c59389e7fc5b1de1c08c4be28ace68f6987293801b1da38542f8354951cd20fa9f307e8e8bcb133ea6905572fffd8b90a1100a1b21b
6
+ metadata.gz: 59e6a4763c2d04a72ffbae080e1b999230faba801307662465bb5fcf94ead89c32a4494af60962807c7f49345fa29f96a271c98dba75c383210dde5b590cbe6c
7
+ data.tar.gz: 7924ce60532cc79c8992dc7f8b435212b890255d4afaac331c19466cb7cc369260946d7254182f07aaeec68d074adcc5015e599b90fed04957f2e42e3eacb0a3
@@ -15,7 +15,7 @@ module Mach
15
15
  # Replace methods in +syms+ with error checking wrappers that
16
16
  # invoke the original method and raise a {SystemCallError}.
17
17
  #
18
- # The original method is invoked, and it's return value is passed
18
+ # The original method is invoked, and its return value is passed
19
19
  # to the block (or a default check). The block should return true
20
20
  # if the return value indicates an error state.
21
21
  def self.error_check(*syms, &is_err)
@@ -16,8 +16,22 @@ module ProcessShared
16
16
  FFI::Platform::LIBSUFFIX
17
17
  end
18
18
 
19
- ffi_lib File.join(File.expand_path(File.dirname(__FILE__)),
20
- 'helper.' + suffix)
19
+ # Ruby 2.1 (also 2.0?) puts extensions into, e.g.
20
+ # $GEM_HOME/extensions/x86_64-linux/2.1.0/static/$gemname-$gemversion,
21
+ # so they aren't in the same dir as this file. Normally that's
22
+ # fine since you're just 'require'ing them, but 'helper.so'
23
+ # isn't a real Ruby extension; it's just a shared lib to
24
+ # export some constants that are only available as macros in
25
+ # libc.
26
+ #
27
+ # Fallback to attempting to load from same directory as this file.
28
+ helper = 'process_shared/posix/helper.' + suffix
29
+ fallback_path = File.expand_path(File.dirname(__FILE__))
30
+ path = $LOAD_PATH.find(fallback_path) do |path|
31
+ File.exists?(File.join(path, helper))
32
+ end
33
+
34
+ ffi_lib File.join(path, helper)
21
35
 
22
36
  [:o_rdwr,
23
37
  :o_creat,
@@ -1,7 +1,5 @@
1
- require 'rubygems' if RUBY_VERSION =~ /^1.8/
2
- gem 'minitest'
3
- require 'minitest/spec'
4
1
  require 'minitest/autorun'
2
+ require 'minitest/spec'
5
3
  require 'minitest/matchers'
6
4
 
7
5
  require 'process_shared'
metadata CHANGED
@@ -1,29 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: process_shared
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1a
5
5
  platform: ruby
6
6
  authors:
7
7
  - Patrick Mahoney
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-12-31 00:00:00.000000000 Z
11
+ date: 2015-06-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ffi
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '1.0'
19
+ version: '0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '1.0'
26
+ version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: ci_reporter
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -86,14 +86,14 @@ dependencies:
86
86
  requirements:
87
87
  - - ">="
88
88
  - !ruby/object:Gem::Version
89
- version: '0'
89
+ version: '10'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - ">="
95
95
  - !ruby/object:Gem::Version
96
- version: '0'
96
+ version: '10'
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: rake-compiler
99
99
  requirement: !ruby/object:Gem::Requirement
@@ -142,7 +142,6 @@ email: pat@polycrystal.org
142
142
  executables: []
143
143
  extensions:
144
144
  - ext/helper/extconf.rb
145
- - ext/pthread_sync_helper/extconf.rb
146
145
  extra_rdoc_files:
147
146
  - README.md
148
147
  - ChangeLog
@@ -153,9 +152,6 @@ files:
153
152
  - README.md
154
153
  - ext/helper/extconf.rb
155
154
  - ext/helper/helper.c
156
- - ext/pthread_sync_helper/extconf.rb
157
- - ext/pthread_sync_helper/pthread_sync_helper.c
158
- - ext/semaphore.c
159
155
  - lib/mach.rb
160
156
  - lib/mach/clock.rb
161
157
  - lib/mach/error.rb
@@ -181,22 +177,15 @@ files:
181
177
  - lib/process_shared/posix/errno.rb
182
178
  - lib/process_shared/posix/libc.rb
183
179
  - lib/process_shared/posix/semaphore.rb
184
- - lib/process_shared/posix/shared_array.rb
185
180
  - lib/process_shared/posix/shared_memory.rb
186
181
  - lib/process_shared/posix/time_spec.rb
187
182
  - lib/process_shared/posix/time_val.rb
188
- - lib/process_shared/posix_call.rb
189
183
  - lib/process_shared/process_error.rb
190
- - lib/process_shared/rt.rb
191
184
  - lib/process_shared/shared_array.rb
192
185
  - lib/process_shared/shared_memory_io.rb
193
186
  - lib/process_shared/synchronizable_semaphore.rb
194
- - lib/process_shared/thread.rb
195
187
  - lib/process_shared/time_spec.rb
196
- - lib/scratch.rb
197
188
  - spec/mach/port_spec.rb
198
- - spec/mach/scratch.rb
199
- - spec/mach/scratch2.rb
200
189
  - spec/mach/semaphore_spec.rb
201
190
  - spec/mach/task_spec.rb
202
191
  - spec/process_shared/binary_semaphore_spec.rb
@@ -224,9 +213,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
224
213
  version: '0'
225
214
  required_rubygems_version: !ruby/object:Gem::Requirement
226
215
  requirements:
227
- - - ">="
216
+ - - ">"
228
217
  - !ruby/object:Gem::Version
229
- version: '0'
218
+ version: 1.3.1
230
219
  requirements: []
231
220
  rubyforge_project:
232
221
  rubygems_version: 2.2.0
@@ -234,3 +223,4 @@ signing_key:
234
223
  specification_version: 4
235
224
  summary: process-shared synchronization primitives
236
225
  test_files: []
226
+ has_rdoc: true
@@ -1,9 +0,0 @@
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")
@@ -1,43 +0,0 @@
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;
@@ -1,623 +0,0 @@
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
- };