You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

686 lines
19 KiB

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