| 1 | n/a | /* |
|---|
| 2 | n/a | * A type which wraps a semaphore |
|---|
| 3 | n/a | * |
|---|
| 4 | n/a | * semaphore.c |
|---|
| 5 | n/a | * |
|---|
| 6 | n/a | * Copyright (c) 2006-2008, R Oudkerk |
|---|
| 7 | n/a | * Licensed to PSF under a Contributor Agreement. |
|---|
| 8 | n/a | */ |
|---|
| 9 | n/a | |
|---|
| 10 | n/a | #include "multiprocessing.h" |
|---|
| 11 | n/a | |
|---|
| 12 | n/a | enum { RECURSIVE_MUTEX, SEMAPHORE }; |
|---|
| 13 | n/a | |
|---|
| 14 | n/a | typedef struct { |
|---|
| 15 | n/a | PyObject_HEAD |
|---|
| 16 | n/a | SEM_HANDLE handle; |
|---|
| 17 | n/a | long last_tid; |
|---|
| 18 | n/a | int count; |
|---|
| 19 | n/a | int maxvalue; |
|---|
| 20 | n/a | int kind; |
|---|
| 21 | n/a | char *name; |
|---|
| 22 | n/a | } SemLockObject; |
|---|
| 23 | n/a | |
|---|
| 24 | n/a | #define ISMINE(o) (o->count > 0 && PyThread_get_thread_ident() == o->last_tid) |
|---|
| 25 | n/a | |
|---|
| 26 | n/a | |
|---|
| 27 | n/a | #ifdef MS_WINDOWS |
|---|
| 28 | n/a | |
|---|
| 29 | n/a | /* |
|---|
| 30 | n/a | * Windows definitions |
|---|
| 31 | n/a | */ |
|---|
| 32 | n/a | |
|---|
| 33 | n/a | #define SEM_FAILED NULL |
|---|
| 34 | n/a | |
|---|
| 35 | n/a | #define SEM_CLEAR_ERROR() SetLastError(0) |
|---|
| 36 | n/a | #define SEM_GET_LAST_ERROR() GetLastError() |
|---|
| 37 | n/a | #define SEM_CREATE(name, val, max) CreateSemaphore(NULL, val, max, NULL) |
|---|
| 38 | n/a | #define SEM_CLOSE(sem) (CloseHandle(sem) ? 0 : -1) |
|---|
| 39 | n/a | #define SEM_GETVALUE(sem, pval) _GetSemaphoreValue(sem, pval) |
|---|
| 40 | n/a | #define SEM_UNLINK(name) 0 |
|---|
| 41 | n/a | |
|---|
| 42 | n/a | static int |
|---|
| 43 | n/a | _GetSemaphoreValue(HANDLE handle, long *value) |
|---|
| 44 | n/a | { |
|---|
| 45 | n/a | long previous; |
|---|
| 46 | n/a | |
|---|
| 47 | n/a | switch (WaitForSingleObjectEx(handle, 0, FALSE)) { |
|---|
| 48 | n/a | case WAIT_OBJECT_0: |
|---|
| 49 | n/a | if (!ReleaseSemaphore(handle, 1, &previous)) |
|---|
| 50 | n/a | return MP_STANDARD_ERROR; |
|---|
| 51 | n/a | *value = previous + 1; |
|---|
| 52 | n/a | return 0; |
|---|
| 53 | n/a | case WAIT_TIMEOUT: |
|---|
| 54 | n/a | *value = 0; |
|---|
| 55 | n/a | return 0; |
|---|
| 56 | n/a | default: |
|---|
| 57 | n/a | return MP_STANDARD_ERROR; |
|---|
| 58 | n/a | } |
|---|
| 59 | n/a | } |
|---|
| 60 | n/a | |
|---|
| 61 | n/a | static PyObject * |
|---|
| 62 | n/a | semlock_acquire(SemLockObject *self, PyObject *args, PyObject *kwds) |
|---|
| 63 | n/a | { |
|---|
| 64 | n/a | int blocking = 1; |
|---|
| 65 | n/a | double timeout; |
|---|
| 66 | n/a | PyObject *timeout_obj = Py_None; |
|---|
| 67 | n/a | DWORD res, full_msecs, nhandles; |
|---|
| 68 | n/a | HANDLE handles[2], sigint_event; |
|---|
| 69 | n/a | |
|---|
| 70 | n/a | static char *kwlist[] = {"block", "timeout", NULL}; |
|---|
| 71 | n/a | |
|---|
| 72 | n/a | if (!PyArg_ParseTupleAndKeywords(args, kwds, "|iO", kwlist, |
|---|
| 73 | n/a | &blocking, &timeout_obj)) |
|---|
| 74 | n/a | return NULL; |
|---|
| 75 | n/a | |
|---|
| 76 | n/a | /* calculate timeout */ |
|---|
| 77 | n/a | if (!blocking) { |
|---|
| 78 | n/a | full_msecs = 0; |
|---|
| 79 | n/a | } else if (timeout_obj == Py_None) { |
|---|
| 80 | n/a | full_msecs = INFINITE; |
|---|
| 81 | n/a | } else { |
|---|
| 82 | n/a | timeout = PyFloat_AsDouble(timeout_obj); |
|---|
| 83 | n/a | if (PyErr_Occurred()) |
|---|
| 84 | n/a | return NULL; |
|---|
| 85 | n/a | timeout *= 1000.0; /* convert to millisecs */ |
|---|
| 86 | n/a | if (timeout < 0.0) { |
|---|
| 87 | n/a | timeout = 0.0; |
|---|
| 88 | n/a | } else if (timeout >= 0.5 * INFINITE) { /* 25 days */ |
|---|
| 89 | n/a | PyErr_SetString(PyExc_OverflowError, |
|---|
| 90 | n/a | "timeout is too large"); |
|---|
| 91 | n/a | return NULL; |
|---|
| 92 | n/a | } |
|---|
| 93 | n/a | full_msecs = (DWORD)(timeout + 0.5); |
|---|
| 94 | n/a | } |
|---|
| 95 | n/a | |
|---|
| 96 | n/a | /* check whether we already own the lock */ |
|---|
| 97 | n/a | if (self->kind == RECURSIVE_MUTEX && ISMINE(self)) { |
|---|
| 98 | n/a | ++self->count; |
|---|
| 99 | n/a | Py_RETURN_TRUE; |
|---|
| 100 | n/a | } |
|---|
| 101 | n/a | |
|---|
| 102 | n/a | /* check whether we can acquire without releasing the GIL and blocking */ |
|---|
| 103 | n/a | if (WaitForSingleObjectEx(self->handle, 0, FALSE) == WAIT_OBJECT_0) { |
|---|
| 104 | n/a | self->last_tid = GetCurrentThreadId(); |
|---|
| 105 | n/a | ++self->count; |
|---|
| 106 | n/a | Py_RETURN_TRUE; |
|---|
| 107 | n/a | } |
|---|
| 108 | n/a | |
|---|
| 109 | n/a | /* prepare list of handles */ |
|---|
| 110 | n/a | nhandles = 0; |
|---|
| 111 | n/a | handles[nhandles++] = self->handle; |
|---|
| 112 | n/a | if (_PyOS_IsMainThread()) { |
|---|
| 113 | n/a | sigint_event = _PyOS_SigintEvent(); |
|---|
| 114 | n/a | assert(sigint_event != NULL); |
|---|
| 115 | n/a | handles[nhandles++] = sigint_event; |
|---|
| 116 | n/a | } |
|---|
| 117 | n/a | else { |
|---|
| 118 | n/a | sigint_event = NULL; |
|---|
| 119 | n/a | } |
|---|
| 120 | n/a | |
|---|
| 121 | n/a | /* do the wait */ |
|---|
| 122 | n/a | Py_BEGIN_ALLOW_THREADS |
|---|
| 123 | n/a | if (sigint_event != NULL) |
|---|
| 124 | n/a | ResetEvent(sigint_event); |
|---|
| 125 | n/a | res = WaitForMultipleObjectsEx(nhandles, handles, FALSE, full_msecs, FALSE); |
|---|
| 126 | n/a | Py_END_ALLOW_THREADS |
|---|
| 127 | n/a | |
|---|
| 128 | n/a | /* handle result */ |
|---|
| 129 | n/a | switch (res) { |
|---|
| 130 | n/a | case WAIT_TIMEOUT: |
|---|
| 131 | n/a | Py_RETURN_FALSE; |
|---|
| 132 | n/a | case WAIT_OBJECT_0 + 0: |
|---|
| 133 | n/a | self->last_tid = GetCurrentThreadId(); |
|---|
| 134 | n/a | ++self->count; |
|---|
| 135 | n/a | Py_RETURN_TRUE; |
|---|
| 136 | n/a | case WAIT_OBJECT_0 + 1: |
|---|
| 137 | n/a | errno = EINTR; |
|---|
| 138 | n/a | return PyErr_SetFromErrno(PyExc_IOError); |
|---|
| 139 | n/a | case WAIT_FAILED: |
|---|
| 140 | n/a | return PyErr_SetFromWindowsErr(0); |
|---|
| 141 | n/a | default: |
|---|
| 142 | n/a | PyErr_Format(PyExc_RuntimeError, "WaitForSingleObject() or " |
|---|
| 143 | n/a | "WaitForMultipleObjects() gave unrecognized " |
|---|
| 144 | n/a | "value %d", res); |
|---|
| 145 | n/a | return NULL; |
|---|
| 146 | n/a | } |
|---|
| 147 | n/a | } |
|---|
| 148 | n/a | |
|---|
| 149 | n/a | static PyObject * |
|---|
| 150 | n/a | semlock_release(SemLockObject *self, PyObject *args) |
|---|
| 151 | n/a | { |
|---|
| 152 | n/a | if (self->kind == RECURSIVE_MUTEX) { |
|---|
| 153 | n/a | if (!ISMINE(self)) { |
|---|
| 154 | n/a | PyErr_SetString(PyExc_AssertionError, "attempt to " |
|---|
| 155 | n/a | "release recursive lock not owned " |
|---|
| 156 | n/a | "by thread"); |
|---|
| 157 | n/a | return NULL; |
|---|
| 158 | n/a | } |
|---|
| 159 | n/a | if (self->count > 1) { |
|---|
| 160 | n/a | --self->count; |
|---|
| 161 | n/a | Py_RETURN_NONE; |
|---|
| 162 | n/a | } |
|---|
| 163 | n/a | assert(self->count == 1); |
|---|
| 164 | n/a | } |
|---|
| 165 | n/a | |
|---|
| 166 | n/a | if (!ReleaseSemaphore(self->handle, 1, NULL)) { |
|---|
| 167 | n/a | if (GetLastError() == ERROR_TOO_MANY_POSTS) { |
|---|
| 168 | n/a | PyErr_SetString(PyExc_ValueError, "semaphore or lock " |
|---|
| 169 | n/a | "released too many times"); |
|---|
| 170 | n/a | return NULL; |
|---|
| 171 | n/a | } else { |
|---|
| 172 | n/a | return PyErr_SetFromWindowsErr(0); |
|---|
| 173 | n/a | } |
|---|
| 174 | n/a | } |
|---|
| 175 | n/a | |
|---|
| 176 | n/a | --self->count; |
|---|
| 177 | n/a | Py_RETURN_NONE; |
|---|
| 178 | n/a | } |
|---|
| 179 | n/a | |
|---|
| 180 | n/a | #else /* !MS_WINDOWS */ |
|---|
| 181 | n/a | |
|---|
| 182 | n/a | /* |
|---|
| 183 | n/a | * Unix definitions |
|---|
| 184 | n/a | */ |
|---|
| 185 | n/a | |
|---|
| 186 | n/a | #define SEM_CLEAR_ERROR() |
|---|
| 187 | n/a | #define SEM_GET_LAST_ERROR() 0 |
|---|
| 188 | n/a | #define SEM_CREATE(name, val, max) sem_open(name, O_CREAT | O_EXCL, 0600, val) |
|---|
| 189 | n/a | #define SEM_CLOSE(sem) sem_close(sem) |
|---|
| 190 | n/a | #define SEM_GETVALUE(sem, pval) sem_getvalue(sem, pval) |
|---|
| 191 | n/a | #define SEM_UNLINK(name) sem_unlink(name) |
|---|
| 192 | n/a | |
|---|
| 193 | n/a | /* OS X 10.4 defines SEM_FAILED as -1 instead of (sem_t *)-1; this gives |
|---|
| 194 | n/a | compiler warnings, and (potentially) undefined behaviour. */ |
|---|
| 195 | n/a | #ifdef __APPLE__ |
|---|
| 196 | n/a | # undef SEM_FAILED |
|---|
| 197 | n/a | # define SEM_FAILED ((sem_t *)-1) |
|---|
| 198 | n/a | #endif |
|---|
| 199 | n/a | |
|---|
| 200 | n/a | #ifndef HAVE_SEM_UNLINK |
|---|
| 201 | n/a | # define sem_unlink(name) 0 |
|---|
| 202 | n/a | #endif |
|---|
| 203 | n/a | |
|---|
| 204 | n/a | #ifndef HAVE_SEM_TIMEDWAIT |
|---|
| 205 | n/a | # define sem_timedwait(sem,deadline) sem_timedwait_save(sem,deadline,_save) |
|---|
| 206 | n/a | |
|---|
| 207 | n/a | static int |
|---|
| 208 | n/a | sem_timedwait_save(sem_t *sem, struct timespec *deadline, PyThreadState *_save) |
|---|
| 209 | n/a | { |
|---|
| 210 | n/a | int res; |
|---|
| 211 | n/a | unsigned long delay, difference; |
|---|
| 212 | n/a | struct timeval now, tvdeadline, tvdelay; |
|---|
| 213 | n/a | |
|---|
| 214 | n/a | errno = 0; |
|---|
| 215 | n/a | tvdeadline.tv_sec = deadline->tv_sec; |
|---|
| 216 | n/a | tvdeadline.tv_usec = deadline->tv_nsec / 1000; |
|---|
| 217 | n/a | |
|---|
| 218 | n/a | for (delay = 0 ; ; delay += 1000) { |
|---|
| 219 | n/a | /* poll */ |
|---|
| 220 | n/a | if (sem_trywait(sem) == 0) |
|---|
| 221 | n/a | return 0; |
|---|
| 222 | n/a | else if (errno != EAGAIN) |
|---|
| 223 | n/a | return MP_STANDARD_ERROR; |
|---|
| 224 | n/a | |
|---|
| 225 | n/a | /* get current time */ |
|---|
| 226 | n/a | if (gettimeofday(&now, NULL) < 0) |
|---|
| 227 | n/a | return MP_STANDARD_ERROR; |
|---|
| 228 | n/a | |
|---|
| 229 | n/a | /* check for timeout */ |
|---|
| 230 | n/a | if (tvdeadline.tv_sec < now.tv_sec || |
|---|
| 231 | n/a | (tvdeadline.tv_sec == now.tv_sec && |
|---|
| 232 | n/a | tvdeadline.tv_usec <= now.tv_usec)) { |
|---|
| 233 | n/a | errno = ETIMEDOUT; |
|---|
| 234 | n/a | return MP_STANDARD_ERROR; |
|---|
| 235 | n/a | } |
|---|
| 236 | n/a | |
|---|
| 237 | n/a | /* calculate how much time is left */ |
|---|
| 238 | n/a | difference = (tvdeadline.tv_sec - now.tv_sec) * 1000000 + |
|---|
| 239 | n/a | (tvdeadline.tv_usec - now.tv_usec); |
|---|
| 240 | n/a | |
|---|
| 241 | n/a | /* check delay not too long -- maximum is 20 msecs */ |
|---|
| 242 | n/a | if (delay > 20000) |
|---|
| 243 | n/a | delay = 20000; |
|---|
| 244 | n/a | if (delay > difference) |
|---|
| 245 | n/a | delay = difference; |
|---|
| 246 | n/a | |
|---|
| 247 | n/a | /* sleep */ |
|---|
| 248 | n/a | tvdelay.tv_sec = delay / 1000000; |
|---|
| 249 | n/a | tvdelay.tv_usec = delay % 1000000; |
|---|
| 250 | n/a | if (select(0, NULL, NULL, NULL, &tvdelay) < 0) |
|---|
| 251 | n/a | return MP_STANDARD_ERROR; |
|---|
| 252 | n/a | |
|---|
| 253 | n/a | /* check for signals */ |
|---|
| 254 | n/a | Py_BLOCK_THREADS |
|---|
| 255 | n/a | res = PyErr_CheckSignals(); |
|---|
| 256 | n/a | Py_UNBLOCK_THREADS |
|---|
| 257 | n/a | |
|---|
| 258 | n/a | if (res) { |
|---|
| 259 | n/a | errno = EINTR; |
|---|
| 260 | n/a | return MP_EXCEPTION_HAS_BEEN_SET; |
|---|
| 261 | n/a | } |
|---|
| 262 | n/a | } |
|---|
| 263 | n/a | } |
|---|
| 264 | n/a | |
|---|
| 265 | n/a | #endif /* !HAVE_SEM_TIMEDWAIT */ |
|---|
| 266 | n/a | |
|---|
| 267 | n/a | static PyObject * |
|---|
| 268 | n/a | semlock_acquire(SemLockObject *self, PyObject *args, PyObject *kwds) |
|---|
| 269 | n/a | { |
|---|
| 270 | n/a | int blocking = 1, res, err = 0; |
|---|
| 271 | n/a | double timeout; |
|---|
| 272 | n/a | PyObject *timeout_obj = Py_None; |
|---|
| 273 | n/a | struct timespec deadline = {0}; |
|---|
| 274 | n/a | struct timeval now; |
|---|
| 275 | n/a | long sec, nsec; |
|---|
| 276 | n/a | |
|---|
| 277 | n/a | static char *kwlist[] = {"block", "timeout", NULL}; |
|---|
| 278 | n/a | |
|---|
| 279 | n/a | if (!PyArg_ParseTupleAndKeywords(args, kwds, "|iO", kwlist, |
|---|
| 280 | n/a | &blocking, &timeout_obj)) |
|---|
| 281 | n/a | return NULL; |
|---|
| 282 | n/a | |
|---|
| 283 | n/a | if (self->kind == RECURSIVE_MUTEX && ISMINE(self)) { |
|---|
| 284 | n/a | ++self->count; |
|---|
| 285 | n/a | Py_RETURN_TRUE; |
|---|
| 286 | n/a | } |
|---|
| 287 | n/a | |
|---|
| 288 | n/a | if (timeout_obj != Py_None) { |
|---|
| 289 | n/a | timeout = PyFloat_AsDouble(timeout_obj); |
|---|
| 290 | n/a | if (PyErr_Occurred()) |
|---|
| 291 | n/a | return NULL; |
|---|
| 292 | n/a | if (timeout < 0.0) |
|---|
| 293 | n/a | timeout = 0.0; |
|---|
| 294 | n/a | |
|---|
| 295 | n/a | if (gettimeofday(&now, NULL) < 0) { |
|---|
| 296 | n/a | PyErr_SetFromErrno(PyExc_OSError); |
|---|
| 297 | n/a | return NULL; |
|---|
| 298 | n/a | } |
|---|
| 299 | n/a | sec = (long) timeout; |
|---|
| 300 | n/a | nsec = (long) (1e9 * (timeout - sec) + 0.5); |
|---|
| 301 | n/a | deadline.tv_sec = now.tv_sec + sec; |
|---|
| 302 | n/a | deadline.tv_nsec = now.tv_usec * 1000 + nsec; |
|---|
| 303 | n/a | deadline.tv_sec += (deadline.tv_nsec / 1000000000); |
|---|
| 304 | n/a | deadline.tv_nsec %= 1000000000; |
|---|
| 305 | n/a | } |
|---|
| 306 | n/a | |
|---|
| 307 | n/a | do { |
|---|
| 308 | n/a | Py_BEGIN_ALLOW_THREADS |
|---|
| 309 | n/a | if (blocking && timeout_obj == Py_None) |
|---|
| 310 | n/a | res = sem_wait(self->handle); |
|---|
| 311 | n/a | else if (!blocking) |
|---|
| 312 | n/a | res = sem_trywait(self->handle); |
|---|
| 313 | n/a | else |
|---|
| 314 | n/a | res = sem_timedwait(self->handle, &deadline); |
|---|
| 315 | n/a | Py_END_ALLOW_THREADS |
|---|
| 316 | n/a | err = errno; |
|---|
| 317 | n/a | if (res == MP_EXCEPTION_HAS_BEEN_SET) |
|---|
| 318 | n/a | break; |
|---|
| 319 | n/a | } while (res < 0 && errno == EINTR && !PyErr_CheckSignals()); |
|---|
| 320 | n/a | |
|---|
| 321 | n/a | if (res < 0) { |
|---|
| 322 | n/a | errno = err; |
|---|
| 323 | n/a | if (errno == EAGAIN || errno == ETIMEDOUT) |
|---|
| 324 | n/a | Py_RETURN_FALSE; |
|---|
| 325 | n/a | else if (errno == EINTR) |
|---|
| 326 | n/a | return NULL; |
|---|
| 327 | n/a | else |
|---|
| 328 | n/a | return PyErr_SetFromErrno(PyExc_OSError); |
|---|
| 329 | n/a | } |
|---|
| 330 | n/a | |
|---|
| 331 | n/a | ++self->count; |
|---|
| 332 | n/a | self->last_tid = PyThread_get_thread_ident(); |
|---|
| 333 | n/a | |
|---|
| 334 | n/a | Py_RETURN_TRUE; |
|---|
| 335 | n/a | } |
|---|
| 336 | n/a | |
|---|
| 337 | n/a | static PyObject * |
|---|
| 338 | n/a | semlock_release(SemLockObject *self, PyObject *args) |
|---|
| 339 | n/a | { |
|---|
| 340 | n/a | if (self->kind == RECURSIVE_MUTEX) { |
|---|
| 341 | n/a | if (!ISMINE(self)) { |
|---|
| 342 | n/a | PyErr_SetString(PyExc_AssertionError, "attempt to " |
|---|
| 343 | n/a | "release recursive lock not owned " |
|---|
| 344 | n/a | "by thread"); |
|---|
| 345 | n/a | return NULL; |
|---|
| 346 | n/a | } |
|---|
| 347 | n/a | if (self->count > 1) { |
|---|
| 348 | n/a | --self->count; |
|---|
| 349 | n/a | Py_RETURN_NONE; |
|---|
| 350 | n/a | } |
|---|
| 351 | n/a | assert(self->count == 1); |
|---|
| 352 | n/a | } else { |
|---|
| 353 | n/a | #ifdef HAVE_BROKEN_SEM_GETVALUE |
|---|
| 354 | n/a | /* We will only check properly the maxvalue == 1 case */ |
|---|
| 355 | n/a | if (self->maxvalue == 1) { |
|---|
| 356 | n/a | /* make sure that already locked */ |
|---|
| 357 | n/a | if (sem_trywait(self->handle) < 0) { |
|---|
| 358 | n/a | if (errno != EAGAIN) { |
|---|
| 359 | n/a | PyErr_SetFromErrno(PyExc_OSError); |
|---|
| 360 | n/a | return NULL; |
|---|
| 361 | n/a | } |
|---|
| 362 | n/a | /* it is already locked as expected */ |
|---|
| 363 | n/a | } else { |
|---|
| 364 | n/a | /* it was not locked so undo wait and raise */ |
|---|
| 365 | n/a | if (sem_post(self->handle) < 0) { |
|---|
| 366 | n/a | PyErr_SetFromErrno(PyExc_OSError); |
|---|
| 367 | n/a | return NULL; |
|---|
| 368 | n/a | } |
|---|
| 369 | n/a | PyErr_SetString(PyExc_ValueError, "semaphore " |
|---|
| 370 | n/a | "or lock released too many " |
|---|
| 371 | n/a | "times"); |
|---|
| 372 | n/a | return NULL; |
|---|
| 373 | n/a | } |
|---|
| 374 | n/a | } |
|---|
| 375 | n/a | #else |
|---|
| 376 | n/a | int sval; |
|---|
| 377 | n/a | |
|---|
| 378 | n/a | /* This check is not an absolute guarantee that the semaphore |
|---|
| 379 | n/a | does not rise above maxvalue. */ |
|---|
| 380 | n/a | if (sem_getvalue(self->handle, &sval) < 0) { |
|---|
| 381 | n/a | return PyErr_SetFromErrno(PyExc_OSError); |
|---|
| 382 | n/a | } else if (sval >= self->maxvalue) { |
|---|
| 383 | n/a | PyErr_SetString(PyExc_ValueError, "semaphore or lock " |
|---|
| 384 | n/a | "released too many times"); |
|---|
| 385 | n/a | return NULL; |
|---|
| 386 | n/a | } |
|---|
| 387 | n/a | #endif |
|---|
| 388 | n/a | } |
|---|
| 389 | n/a | |
|---|
| 390 | n/a | if (sem_post(self->handle) < 0) |
|---|
| 391 | n/a | return PyErr_SetFromErrno(PyExc_OSError); |
|---|
| 392 | n/a | |
|---|
| 393 | n/a | --self->count; |
|---|
| 394 | n/a | Py_RETURN_NONE; |
|---|
| 395 | n/a | } |
|---|
| 396 | n/a | |
|---|
| 397 | n/a | #endif /* !MS_WINDOWS */ |
|---|
| 398 | n/a | |
|---|
| 399 | n/a | /* |
|---|
| 400 | n/a | * All platforms |
|---|
| 401 | n/a | */ |
|---|
| 402 | n/a | |
|---|
| 403 | n/a | static PyObject * |
|---|
| 404 | n/a | newsemlockobject(PyTypeObject *type, SEM_HANDLE handle, int kind, int maxvalue, |
|---|
| 405 | n/a | char *name) |
|---|
| 406 | n/a | { |
|---|
| 407 | n/a | SemLockObject *self; |
|---|
| 408 | n/a | |
|---|
| 409 | n/a | self = PyObject_New(SemLockObject, type); |
|---|
| 410 | n/a | if (!self) |
|---|
| 411 | n/a | return NULL; |
|---|
| 412 | n/a | self->handle = handle; |
|---|
| 413 | n/a | self->kind = kind; |
|---|
| 414 | n/a | self->count = 0; |
|---|
| 415 | n/a | self->last_tid = 0; |
|---|
| 416 | n/a | self->maxvalue = maxvalue; |
|---|
| 417 | n/a | self->name = name; |
|---|
| 418 | n/a | return (PyObject*)self; |
|---|
| 419 | n/a | } |
|---|
| 420 | n/a | |
|---|
| 421 | n/a | static PyObject * |
|---|
| 422 | n/a | semlock_new(PyTypeObject *type, PyObject *args, PyObject *kwds) |
|---|
| 423 | n/a | { |
|---|
| 424 | n/a | SEM_HANDLE handle = SEM_FAILED; |
|---|
| 425 | n/a | int kind, maxvalue, value, unlink; |
|---|
| 426 | n/a | PyObject *result; |
|---|
| 427 | n/a | char *name, *name_copy = NULL; |
|---|
| 428 | n/a | static char *kwlist[] = {"kind", "value", "maxvalue", "name", "unlink", |
|---|
| 429 | n/a | NULL}; |
|---|
| 430 | n/a | |
|---|
| 431 | n/a | if (!PyArg_ParseTupleAndKeywords(args, kwds, "iiisi", kwlist, |
|---|
| 432 | n/a | &kind, &value, &maxvalue, &name, &unlink)) |
|---|
| 433 | n/a | return NULL; |
|---|
| 434 | n/a | |
|---|
| 435 | n/a | if (kind != RECURSIVE_MUTEX && kind != SEMAPHORE) { |
|---|
| 436 | n/a | PyErr_SetString(PyExc_ValueError, "unrecognized kind"); |
|---|
| 437 | n/a | return NULL; |
|---|
| 438 | n/a | } |
|---|
| 439 | n/a | |
|---|
| 440 | n/a | if (!unlink) { |
|---|
| 441 | n/a | name_copy = PyMem_Malloc(strlen(name) + 1); |
|---|
| 442 | n/a | if (name_copy == NULL) |
|---|
| 443 | n/a | goto failure; |
|---|
| 444 | n/a | strcpy(name_copy, name); |
|---|
| 445 | n/a | } |
|---|
| 446 | n/a | |
|---|
| 447 | n/a | SEM_CLEAR_ERROR(); |
|---|
| 448 | n/a | handle = SEM_CREATE(name, value, maxvalue); |
|---|
| 449 | n/a | /* On Windows we should fail if GetLastError()==ERROR_ALREADY_EXISTS */ |
|---|
| 450 | n/a | if (handle == SEM_FAILED || SEM_GET_LAST_ERROR() != 0) |
|---|
| 451 | n/a | goto failure; |
|---|
| 452 | n/a | |
|---|
| 453 | n/a | if (unlink && SEM_UNLINK(name) < 0) |
|---|
| 454 | n/a | goto failure; |
|---|
| 455 | n/a | |
|---|
| 456 | n/a | result = newsemlockobject(type, handle, kind, maxvalue, name_copy); |
|---|
| 457 | n/a | if (!result) |
|---|
| 458 | n/a | goto failure; |
|---|
| 459 | n/a | |
|---|
| 460 | n/a | return result; |
|---|
| 461 | n/a | |
|---|
| 462 | n/a | failure: |
|---|
| 463 | n/a | if (handle != SEM_FAILED) |
|---|
| 464 | n/a | SEM_CLOSE(handle); |
|---|
| 465 | n/a | PyMem_Free(name_copy); |
|---|
| 466 | n/a | _PyMp_SetError(NULL, MP_STANDARD_ERROR); |
|---|
| 467 | n/a | return NULL; |
|---|
| 468 | n/a | } |
|---|
| 469 | n/a | |
|---|
| 470 | n/a | static PyObject * |
|---|
| 471 | n/a | semlock_rebuild(PyTypeObject *type, PyObject *args) |
|---|
| 472 | n/a | { |
|---|
| 473 | n/a | SEM_HANDLE handle; |
|---|
| 474 | n/a | int kind, maxvalue; |
|---|
| 475 | n/a | char *name, *name_copy = NULL; |
|---|
| 476 | n/a | |
|---|
| 477 | n/a | if (!PyArg_ParseTuple(args, F_SEM_HANDLE "iiz", |
|---|
| 478 | n/a | &handle, &kind, &maxvalue, &name)) |
|---|
| 479 | n/a | return NULL; |
|---|
| 480 | n/a | |
|---|
| 481 | n/a | if (name != NULL) { |
|---|
| 482 | n/a | name_copy = PyMem_Malloc(strlen(name) + 1); |
|---|
| 483 | n/a | if (name_copy == NULL) |
|---|
| 484 | n/a | return PyErr_NoMemory(); |
|---|
| 485 | n/a | strcpy(name_copy, name); |
|---|
| 486 | n/a | } |
|---|
| 487 | n/a | |
|---|
| 488 | n/a | #ifndef MS_WINDOWS |
|---|
| 489 | n/a | if (name != NULL) { |
|---|
| 490 | n/a | handle = sem_open(name, 0); |
|---|
| 491 | n/a | if (handle == SEM_FAILED) { |
|---|
| 492 | n/a | PyMem_Free(name_copy); |
|---|
| 493 | n/a | return PyErr_SetFromErrno(PyExc_OSError); |
|---|
| 494 | n/a | } |
|---|
| 495 | n/a | } |
|---|
| 496 | n/a | #endif |
|---|
| 497 | n/a | |
|---|
| 498 | n/a | return newsemlockobject(type, handle, kind, maxvalue, name_copy); |
|---|
| 499 | n/a | } |
|---|
| 500 | n/a | |
|---|
| 501 | n/a | static void |
|---|
| 502 | n/a | semlock_dealloc(SemLockObject* self) |
|---|
| 503 | n/a | { |
|---|
| 504 | n/a | if (self->handle != SEM_FAILED) |
|---|
| 505 | n/a | SEM_CLOSE(self->handle); |
|---|
| 506 | n/a | PyMem_Free(self->name); |
|---|
| 507 | n/a | PyObject_Del(self); |
|---|
| 508 | n/a | } |
|---|
| 509 | n/a | |
|---|
| 510 | n/a | static PyObject * |
|---|
| 511 | n/a | semlock_count(SemLockObject *self) |
|---|
| 512 | n/a | { |
|---|
| 513 | n/a | return PyLong_FromLong((long)self->count); |
|---|
| 514 | n/a | } |
|---|
| 515 | n/a | |
|---|
| 516 | n/a | static PyObject * |
|---|
| 517 | n/a | semlock_ismine(SemLockObject *self) |
|---|
| 518 | n/a | { |
|---|
| 519 | n/a | /* only makes sense for a lock */ |
|---|
| 520 | n/a | return PyBool_FromLong(ISMINE(self)); |
|---|
| 521 | n/a | } |
|---|
| 522 | n/a | |
|---|
| 523 | n/a | static PyObject * |
|---|
| 524 | n/a | semlock_getvalue(SemLockObject *self) |
|---|
| 525 | n/a | { |
|---|
| 526 | n/a | #ifdef HAVE_BROKEN_SEM_GETVALUE |
|---|
| 527 | n/a | PyErr_SetNone(PyExc_NotImplementedError); |
|---|
| 528 | n/a | return NULL; |
|---|
| 529 | n/a | #else |
|---|
| 530 | n/a | int sval; |
|---|
| 531 | n/a | if (SEM_GETVALUE(self->handle, &sval) < 0) |
|---|
| 532 | n/a | return _PyMp_SetError(NULL, MP_STANDARD_ERROR); |
|---|
| 533 | n/a | /* some posix implementations use negative numbers to indicate |
|---|
| 534 | n/a | the number of waiting threads */ |
|---|
| 535 | n/a | if (sval < 0) |
|---|
| 536 | n/a | sval = 0; |
|---|
| 537 | n/a | return PyLong_FromLong((long)sval); |
|---|
| 538 | n/a | #endif |
|---|
| 539 | n/a | } |
|---|
| 540 | n/a | |
|---|
| 541 | n/a | static PyObject * |
|---|
| 542 | n/a | semlock_iszero(SemLockObject *self) |
|---|
| 543 | n/a | { |
|---|
| 544 | n/a | #ifdef HAVE_BROKEN_SEM_GETVALUE |
|---|
| 545 | n/a | if (sem_trywait(self->handle) < 0) { |
|---|
| 546 | n/a | if (errno == EAGAIN) |
|---|
| 547 | n/a | Py_RETURN_TRUE; |
|---|
| 548 | n/a | return _PyMp_SetError(NULL, MP_STANDARD_ERROR); |
|---|
| 549 | n/a | } else { |
|---|
| 550 | n/a | if (sem_post(self->handle) < 0) |
|---|
| 551 | n/a | return _PyMp_SetError(NULL, MP_STANDARD_ERROR); |
|---|
| 552 | n/a | Py_RETURN_FALSE; |
|---|
| 553 | n/a | } |
|---|
| 554 | n/a | #else |
|---|
| 555 | n/a | int sval; |
|---|
| 556 | n/a | if (SEM_GETVALUE(self->handle, &sval) < 0) |
|---|
| 557 | n/a | return _PyMp_SetError(NULL, MP_STANDARD_ERROR); |
|---|
| 558 | n/a | return PyBool_FromLong((long)sval == 0); |
|---|
| 559 | n/a | #endif |
|---|
| 560 | n/a | } |
|---|
| 561 | n/a | |
|---|
| 562 | n/a | static PyObject * |
|---|
| 563 | n/a | semlock_afterfork(SemLockObject *self) |
|---|
| 564 | n/a | { |
|---|
| 565 | n/a | self->count = 0; |
|---|
| 566 | n/a | Py_RETURN_NONE; |
|---|
| 567 | n/a | } |
|---|
| 568 | n/a | |
|---|
| 569 | n/a | /* |
|---|
| 570 | n/a | * Semaphore methods |
|---|
| 571 | n/a | */ |
|---|
| 572 | n/a | |
|---|
| 573 | n/a | static PyMethodDef semlock_methods[] = { |
|---|
| 574 | n/a | {"acquire", (PyCFunction)semlock_acquire, METH_VARARGS | METH_KEYWORDS, |
|---|
| 575 | n/a | "acquire the semaphore/lock"}, |
|---|
| 576 | n/a | {"release", (PyCFunction)semlock_release, METH_NOARGS, |
|---|
| 577 | n/a | "release the semaphore/lock"}, |
|---|
| 578 | n/a | {"__enter__", (PyCFunction)semlock_acquire, METH_VARARGS | METH_KEYWORDS, |
|---|
| 579 | n/a | "enter the semaphore/lock"}, |
|---|
| 580 | n/a | {"__exit__", (PyCFunction)semlock_release, METH_VARARGS, |
|---|
| 581 | n/a | "exit the semaphore/lock"}, |
|---|
| 582 | n/a | {"_count", (PyCFunction)semlock_count, METH_NOARGS, |
|---|
| 583 | n/a | "num of `acquire()`s minus num of `release()`s for this process"}, |
|---|
| 584 | n/a | {"_is_mine", (PyCFunction)semlock_ismine, METH_NOARGS, |
|---|
| 585 | n/a | "whether the lock is owned by this thread"}, |
|---|
| 586 | n/a | {"_get_value", (PyCFunction)semlock_getvalue, METH_NOARGS, |
|---|
| 587 | n/a | "get the value of the semaphore"}, |
|---|
| 588 | n/a | {"_is_zero", (PyCFunction)semlock_iszero, METH_NOARGS, |
|---|
| 589 | n/a | "returns whether semaphore has value zero"}, |
|---|
| 590 | n/a | {"_rebuild", (PyCFunction)semlock_rebuild, METH_VARARGS | METH_CLASS, |
|---|
| 591 | n/a | ""}, |
|---|
| 592 | n/a | {"_after_fork", (PyCFunction)semlock_afterfork, METH_NOARGS, |
|---|
| 593 | n/a | "rezero the net acquisition count after fork()"}, |
|---|
| 594 | n/a | {NULL} |
|---|
| 595 | n/a | }; |
|---|
| 596 | n/a | |
|---|
| 597 | n/a | /* |
|---|
| 598 | n/a | * Member table |
|---|
| 599 | n/a | */ |
|---|
| 600 | n/a | |
|---|
| 601 | n/a | static PyMemberDef semlock_members[] = { |
|---|
| 602 | n/a | {"handle", T_SEM_HANDLE, offsetof(SemLockObject, handle), READONLY, |
|---|
| 603 | n/a | ""}, |
|---|
| 604 | n/a | {"kind", T_INT, offsetof(SemLockObject, kind), READONLY, |
|---|
| 605 | n/a | ""}, |
|---|
| 606 | n/a | {"maxvalue", T_INT, offsetof(SemLockObject, maxvalue), READONLY, |
|---|
| 607 | n/a | ""}, |
|---|
| 608 | n/a | {"name", T_STRING, offsetof(SemLockObject, name), READONLY, |
|---|
| 609 | n/a | ""}, |
|---|
| 610 | n/a | {NULL} |
|---|
| 611 | n/a | }; |
|---|
| 612 | n/a | |
|---|
| 613 | n/a | /* |
|---|
| 614 | n/a | * Semaphore type |
|---|
| 615 | n/a | */ |
|---|
| 616 | n/a | |
|---|
| 617 | n/a | PyTypeObject _PyMp_SemLockType = { |
|---|
| 618 | n/a | PyVarObject_HEAD_INIT(NULL, 0) |
|---|
| 619 | n/a | /* tp_name */ "_multiprocessing.SemLock", |
|---|
| 620 | n/a | /* tp_basicsize */ sizeof(SemLockObject), |
|---|
| 621 | n/a | /* tp_itemsize */ 0, |
|---|
| 622 | n/a | /* tp_dealloc */ (destructor)semlock_dealloc, |
|---|
| 623 | n/a | /* tp_print */ 0, |
|---|
| 624 | n/a | /* tp_getattr */ 0, |
|---|
| 625 | n/a | /* tp_setattr */ 0, |
|---|
| 626 | n/a | /* tp_reserved */ 0, |
|---|
| 627 | n/a | /* tp_repr */ 0, |
|---|
| 628 | n/a | /* tp_as_number */ 0, |
|---|
| 629 | n/a | /* tp_as_sequence */ 0, |
|---|
| 630 | n/a | /* tp_as_mapping */ 0, |
|---|
| 631 | n/a | /* tp_hash */ 0, |
|---|
| 632 | n/a | /* tp_call */ 0, |
|---|
| 633 | n/a | /* tp_str */ 0, |
|---|
| 634 | n/a | /* tp_getattro */ 0, |
|---|
| 635 | n/a | /* tp_setattro */ 0, |
|---|
| 636 | n/a | /* tp_as_buffer */ 0, |
|---|
| 637 | n/a | /* tp_flags */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, |
|---|
| 638 | n/a | /* tp_doc */ "Semaphore/Mutex type", |
|---|
| 639 | n/a | /* tp_traverse */ 0, |
|---|
| 640 | n/a | /* tp_clear */ 0, |
|---|
| 641 | n/a | /* tp_richcompare */ 0, |
|---|
| 642 | n/a | /* tp_weaklistoffset */ 0, |
|---|
| 643 | n/a | /* tp_iter */ 0, |
|---|
| 644 | n/a | /* tp_iternext */ 0, |
|---|
| 645 | n/a | /* tp_methods */ semlock_methods, |
|---|
| 646 | n/a | /* tp_members */ semlock_members, |
|---|
| 647 | n/a | /* tp_getset */ 0, |
|---|
| 648 | n/a | /* tp_base */ 0, |
|---|
| 649 | n/a | /* tp_dict */ 0, |
|---|
| 650 | n/a | /* tp_descr_get */ 0, |
|---|
| 651 | n/a | /* tp_descr_set */ 0, |
|---|
| 652 | n/a | /* tp_dictoffset */ 0, |
|---|
| 653 | n/a | /* tp_init */ 0, |
|---|
| 654 | n/a | /* tp_alloc */ 0, |
|---|
| 655 | n/a | /* tp_new */ semlock_new, |
|---|
| 656 | n/a | }; |
|---|
| 657 | n/a | |
|---|
| 658 | n/a | /* |
|---|
| 659 | n/a | * Function to unlink semaphore names |
|---|
| 660 | n/a | */ |
|---|
| 661 | n/a | |
|---|
| 662 | n/a | PyObject * |
|---|
| 663 | n/a | _PyMp_sem_unlink(PyObject *ignore, PyObject *args) |
|---|
| 664 | n/a | { |
|---|
| 665 | n/a | char *name; |
|---|
| 666 | n/a | |
|---|
| 667 | n/a | if (!PyArg_ParseTuple(args, "s", &name)) |
|---|
| 668 | n/a | return NULL; |
|---|
| 669 | n/a | |
|---|
| 670 | n/a | if (SEM_UNLINK(name) < 0) { |
|---|
| 671 | n/a | _PyMp_SetError(NULL, MP_STANDARD_ERROR); |
|---|
| 672 | n/a | return NULL; |
|---|
| 673 | n/a | } |
|---|
| 674 | n/a | |
|---|
| 675 | n/a | Py_RETURN_NONE; |
|---|
| 676 | n/a | } |
|---|