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 +4 -4
- data/lib/mach/functions.rb +1 -1
- data/lib/process_shared/posix/libc.rb +16 -2
- data/spec/spec_helper.rb +1 -3
- metadata +11 -21
- data/ext/pthread_sync_helper/extconf.rb +0 -9
- data/ext/pthread_sync_helper/pthread_sync_helper.c +0 -43
- data/ext/semaphore.c +0 -623
- data/lib/process_shared/posix/shared_array.rb +0 -71
- data/lib/process_shared/posix_call.rb +0 -29
- data/lib/process_shared/rt.rb +0 -21
- data/lib/process_shared/thread.rb +0 -30
- data/lib/scratch.rb +0 -300
- data/spec/mach/scratch.rb +0 -67
- data/spec/mach/scratch2.rb +0 -78
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 42192608a911df5503886fa0f851a7cd23f13348
|
4
|
+
data.tar.gz: 1f8db3382f895196e5bb7edb9818d1a414186740
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 59e6a4763c2d04a72ffbae080e1b999230faba801307662465bb5fcf94ead89c32a4494af60962807c7f49345fa29f96a271c98dba75c383210dde5b590cbe6c
|
7
|
+
data.tar.gz: 7924ce60532cc79c8992dc7f8b435212b890255d4afaac331c19466cb7cc369260946d7254182f07aaeec68d074adcc5015e599b90fed04957f2e42e3eacb0a3
|
data/lib/mach/functions.rb
CHANGED
@@ -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
|
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
|
-
|
20
|
-
|
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,
|
data/spec/spec_helper.rb
CHANGED
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.
|
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:
|
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: '
|
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: '
|
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: '
|
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: '
|
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:
|
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,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;
|
data/ext/semaphore.c
DELETED
@@ -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
|
-
};
|