Skip to content

Commit 47f3132

Browse files
committed
Fix bugs in sem_unlink and semlock_dealloc
1 parent fdaddcb commit 47f3132

2 files changed

Lines changed: 109 additions & 79 deletions

File tree

Modules/_multiprocessing/semaphore.c

Lines changed: 102 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -386,19 +386,16 @@ _get_constant_semlock(PyObject *self)
386386
return 0;
387387
PyTypeObject *semlock_type = Py_TYPE(self);
388388
if (semlock_type == NULL) {
389-
puts("Cannot get type of self");
390389
return -1;
391390
}
392391

393392
PyObject *module = PyType_GetModule(semlock_type);
394393
if (module == NULL) {
395-
puts("Cannot get type of self");
396394
return -1;
397395
}
398396

399397
PyObject *py_name = PyObject_GetAttrString(module, "_MACOSX_SHAREDMEM_NAME");
400398
if (py_name == NULL) {
401-
puts("Cannot get shared memory name from module");
402399
Py_DECREF(py_name);
403400
return -1;
404401
}
@@ -481,13 +478,13 @@ release_lock(SEM_HANDLE handle)
481478
}
482479

483480
static int
484-
exists_lock(SEM_HANDLE handle)
481+
exist_lock(SEM_HANDLE handle)
485482
{
486483
int res = -1;
487484
int err = 0;
488485

489486
if (handle == NULL || handle == SEM_FAILED) {
490-
DEBUG_PID_FUNC("0", handle, (unsigned long)errno, "Sem never createt");
487+
DEBUG_PID_FUNC("0", handle, (unsigned long)errno, "Sem never created");
491488
shm_semlock_counters.state_this = THIS_NOT_OPEN;
492489
return 0;
493490
}
@@ -656,32 +653,28 @@ Shared memory management
656653
*/
657654

658655
static int
659-
delete_shm_semlock_counters(int lock_shm)
656+
delete_shm_semlock_counters(void)
660657
{
661-
int n_sems = 0;
662-
658+
int res = - 1;
663659
if (shm_semlock_counters.handle_glock != SEM_FAILED &&
664660
shm_semlock_counters.state_this == THIS_AVAILABLE) {
665661

666-
n_sems = shm_semlock_counters.header->n_semlocks;
667-
if (n_sems == 0) {
668-
DEBUG_PID_FUNC(shm_semlock_counters.name_shm, shm_semlock_counters.handle_shm,
669-
0, "remove glock and shared mem");
670-
munmap(shm_semlock_counters.header,
671-
shm_semlock_counters.header->size_shm);
672-
if (shm_semlock_counters.handle_shm > 0) {
673-
close(shm_semlock_counters.handle_shm);
674-
shm_semlock_counters.handle_shm = (MEMORY_HANDLE)0;
675-
}
676-
Py_BEGIN_ALLOW_THREADS
677-
shm_unlink(shm_semlock_counters.name_shm);
678-
Py_END_ALLOW_THREADS
679-
shm_semlock_counters.header = NULL;
680-
shm_semlock_counters.counters = NULL;
681-
shm_semlock_counters.state_this = THIS_CLOSED;
662+
DEBUG_PID_FUNC(shm_semlock_counters.name_shm, shm_semlock_counters.handle_shm,
663+
0, "remove glock and shared mem");
664+
res = munmap(shm_semlock_counters.header,
665+
shm_semlock_counters.header->size_shm);
666+
if (shm_semlock_counters.handle_shm > 0) {
667+
res = close(shm_semlock_counters.handle_shm);
668+
shm_semlock_counters.handle_shm = (MEMORY_HANDLE)0;
682669
}
670+
Py_BEGIN_ALLOW_THREADS
671+
res = shm_unlink(shm_semlock_counters.name_shm);
672+
Py_END_ALLOW_THREADS
673+
shm_semlock_counters.header = NULL;
674+
shm_semlock_counters.counters = NULL;
675+
shm_semlock_counters.state_this = THIS_CLOSED;
683676
}
684-
return n_sems;
677+
return res;
685678
}
686679

687680
static int
@@ -911,10 +904,9 @@ Name is unique and create from SemLock python class.
911904
static char *gh_name = "_gh125828";
912905

913906
static char *
914-
_build_sem_name(char *buf, const char *name)
907+
_build_mutex_name(char *buf, int size, const char *name)
915908
{
916-
strcpy(buf, name);
917-
strcat(buf, gh_name);
909+
PyOS_snprintf(buf, size, "%s%s", name, gh_name);
918910
return buf;
919911
}
920912

@@ -994,13 +986,14 @@ connect_counter(SemLockObject *self)
994986
Create a new CounterObject for a Semaphore, from `SemLock_Impl`.
995987
*/
996988
static CounterObject *
997-
new_counter(SemLockObject *self, const char *name, int value)
989+
new_counter(SemLockObject *self, const char *name, int value, int unlink)
998990
{
999991
CounterObject *counter = _search_counter_free_slot();
1000992
if (counter) {
1001993
strcpy(counter->sem_name, name);
1002994
counter->internal_value = value;
1003995
counter->n_instances = 0;
996+
counter->unlink = unlink;
1004997
counter->ctimestamp = time(NULL);
1005998

1006999
// Update header.
@@ -1022,14 +1015,12 @@ remove_counter(CounterObject *counter)
10221015
{
10231016
int res = -1;
10241017
DEBUG_PID_FUNC(counter->sem_name, 0, counter, "");
1025-
10261018
memset(counter, 0, sizeof(CounterObject));
10271019
--shm_semlock_counters.header->n_semlocks;
1028-
/* --- */
1029-
if (shm_semlock_counters.header->n_semlocks == 0) {
1030-
res = delete_shm_semlock_counters(false);
1020+
1021+
if (!shm_semlock_counters.header->n_semlocks) {
1022+
res = delete_shm_semlock_counters();
10311023
}
1032-
/* -- */
10331024
return res;
10341025
}
10351026

@@ -1314,16 +1305,9 @@ _multiprocessing_SemLock_impl(PyTypeObject *type, int kind, int value,
13141305
semlock = _SemLockObject_CAST(result);
13151306
if (ISSEMAPHORE(semlock)) {
13161307
PyMutex_Lock(&shm_semlock_counters.shm_counters_mutex);
1317-
if (!exists_lock(shm_semlock_counters.handle_glock) ||
1308+
if (!exist_lock(shm_semlock_counters.handle_glock) ||
13181309
shm_semlock_counters.state_this != THIS_AVAILABLE) {
1319-
if (!strlen(name_shm)) {
1320-
if (_get_constant_semlock(result) < 0) {
1321-
PyMutex_Unlock(&shm_semlock_counters.shm_counters_mutex);
1322-
goto failure;
1323-
}
1324-
DEBUG_PID_FUNC(name_shm, 0, counter, "SHM NAME");
1325-
DEBUG_PID_FUNC(name_glock, 0, counter, "LOCK NAME");
1326-
}
1310+
13271311
if (create_shm_semlock_counters(name) < 0) {
13281312
// if (_create_shm_semlock_counters(name) < 0) {
13291313
PyMutex_Unlock(&shm_semlock_counters.shm_counters_mutex);
@@ -1335,9 +1319,9 @@ _multiprocessing_SemLock_impl(PyTypeObject *type, int kind, int value,
13351319
// error is set in ACQUIRE/RELEASE_* macros.
13361320
if (!ACQUIRE_GLOCK) // error set in acquire_lock function
13371321
goto failure;
1338-
handle_mutex = SEM_CREATE(_build_sem_name(mutex_name, name), 1, 1);
1322+
handle_mutex = SEM_CREATE(_build_mutex_name(mutex_name, SIZE_MUTEX_NAME, name), 1, 1);
13391323
if (handle_mutex != SEM_FAILED) {
1340-
counter = new_counter(semlock, name, value);
1324+
counter = new_counter(semlock, name, value, unlink);
13411325
if(counter) {
13421326
semlock->handle_mutex = handle_mutex;
13431327
semlock->counter = counter;
@@ -1448,14 +1432,8 @@ _multiprocessing_SemLock__rebuild_impl(PyTypeObject *type, SEM_HANDLE handle,
14481432
semlock = _SemLockObject_CAST(result);
14491433
if (ISSEMAPHORE(semlock)) {
14501434
PyMutex_Lock(&shm_semlock_counters.shm_counters_mutex);
1451-
if (!exists_lock(shm_semlock_counters.handle_glock) ||
1435+
if (!exist_lock(shm_semlock_counters.handle_glock) ||
14521436
shm_semlock_counters.state_this != THIS_AVAILABLE) {
1453-
if (!strlen(name_shm)) {
1454-
if (_get_constant_semlock(result) < 0) {
1455-
PyMutex_Unlock(&shm_semlock_counters.shm_counters_mutex);
1456-
goto failure;
1457-
}
1458-
}
14591437
if (create_shm_semlock_counters(name) < 0) {
14601438
// if (_connect_shm_semlock_counters(name) < 0) {
14611439
PyMutex_Unlock(&shm_semlock_counters.shm_counters_mutex);
@@ -1468,7 +1446,7 @@ _multiprocessing_SemLock__rebuild_impl(PyTypeObject *type, SEM_HANDLE handle,
14681446
goto failure;
14691447
}
14701448
// error is set in ACQUIRE/RELEASE_* macros.
1471-
handle_mutex = sem_open(_build_sem_name(mutex_name, name), 0);
1449+
handle_mutex = sem_open(_build_mutex_name(mutex_name, SIZE_MUTEX_NAME, name), 0);
14721450
if (handle_mutex != SEM_FAILED) {
14731451
counter = connect_counter(semlock);
14741452
if (counter) {
@@ -1503,8 +1481,8 @@ _multiprocessing_SemLock__rebuild_impl(PyTypeObject *type, SEM_HANDLE handle,
15031481
}
15041482
if (semlock->handle_mutex != SEM_FAILED) {
15051483
SEM_CLOSE(semlock->handle_mutex);
1506-
}
15071484

1485+
}
15081486
PyObject_GC_UnTrack(semlock);
15091487
type->tp_free(semlock);
15101488
Py_DECREF(type);
@@ -1529,27 +1507,35 @@ semlock_dealloc(SemLockObject* self)
15291507
}
15301508

15311509
#ifdef HAVE_BROKEN_SEM_GETVALUE
1532-
int res = -1;
15331510
if (ISSEMAPHORE(self)) {
1511+
/*
1512+
In "forkserver" and "fork" start method, there are as many calls to
1513+
semlock_impl as calls to semlock_dealloc
1514+
In "spawn" start method, there are as calls to semlock_dealloc as
1515+
calls to semlock_impl plus calls to semlock_rebuild.
1516+
Here, it's not possible to known to teh real start method.
1517+
So we have to search if sempahore already exists yet.
1518+
*/
1519+
int n_opened_sems = -1;
1520+
CounterObject *counter = NULL;
1521+
15341522
if (self->handle_mutex != SEM_FAILED) {
15351523
SEM_CLOSE(self->handle_mutex);
15361524
}
1537-
1538-
if (ACQUIRE_GLOCK) {
1539-
DEBUG_PID_FUNC(self->name, self->handle_mutex, self->counter, "");
1540-
if (self->counter) {
1541-
DEBUG_PID_FUNC(self->name, self->handle_mutex, self->counter, "decref counter");
1542-
--self->counter->n_instances;
1543-
if (!self->counter->n_instances) {
1544-
res = remove_counter(self->counter);
1545-
self->counter = NULL;
1546-
}
1547-
}
1525+
DEBUG_PID_FUNC(self->name, self->handle, self->counter, "handle mutex closed");
1526+
1527+
if (EXIST_GLOCK && ACQUIRE_GLOCK) {
1528+
DEBUG_PID_FUNC(self->name, self->handle_mutex, self->counter, "unlink is one");
1529+
if (self->counter->unlink == 1) {
1530+
n_opened_sems = remove_counter(self->counter);
1531+
DEBUG_PID_FUNC(self->name, self->handle_mutex, self->counter, "remove counter");
1532+
}
15481533
RELEASE_GLOCK;
1534+
if (n_opened_sems == 0) {
1535+
delete_glock();
1536+
}
15491537
}
1550-
if (!res ) {
1551-
delete_glock();
1552-
}
1538+
self->counter = NULL;
15531539
}
15541540
#endif /* HAVE_BROKEN_SEM_GETVALUE */
15551541

@@ -1780,7 +1766,7 @@ PyType_Spec _PyMp_SemLockType_spec = {
17801766
* Function to unlink semaphore names
17811767
*/
17821768

1783-
PyObject *
1769+
PyObject *
17841770
_PyMp_sem_unlink(const char *name)
17851771
{
17861772
if (SEM_UNLINK(name) < 0) {
@@ -1790,9 +1776,52 @@ _PyMp_sem_unlink(const char *name)
17901776

17911777
#ifdef HAVE_BROKEN_SEM_GETVALUE
17921778
char mutex_name[SIZE_MUTEX_NAME];
1793-
1794-
// Could failed if this not a semaphore
1795-
SEM_UNLINK(_build_sem_name(mutex_name, name));
1779+
CounterObject *counter = NULL;
1780+
int n_opened_sems = -1;
1781+
1782+
if (SEM_UNLINK(_build_mutex_name(mutex_name, SIZE_MUTEX_NAME, name)) == 0) {
1783+
/*
1784+
So the only place where we could set unlink flag to 1 is there because this function is called
1785+
only per semaphore.
1786+
Note that in "fork" start method, this function is never called, unlink flag is always set to 0.
1787+
*/
1788+
if (EXIST_GLOCK && ACQUIRE_GLOCK) {
1789+
counter = _search_counter_from_sem_name(name);
1790+
if (counter) {
1791+
DEBUG_PID_FUNC(name, 0, counter, "unlink sem");
1792+
n_opened_sems = remove_counter(counter);
1793+
}
1794+
RELEASE_GLOCK;
1795+
if (!n_opened_sems) {
1796+
delete_glock();
1797+
}
1798+
}
1799+
/*
1800+
if (EXIST_GLOCK && ACQUIRE_GLOCK) {
1801+
counter = _search_counter_from_sem_name(name);
1802+
if (counter) {
1803+
DEBUG_PID_FUNC(name, 0, counter, "set unlink to 1");
1804+
counter->unlink = 1;
1805+
}
1806+
RELEASE_GLOCK;
1807+
}
1808+
*/
1809+
/*
1810+
if (EXIST_GLOCK && ACQUIRE_GLOCK) {
1811+
puts("unlink sem, search counter and remove it");
1812+
counter = _search_counter_from_sem_name(name);
1813+
if (counter) {
1814+
DEBUG_PID_FUNC(name, 0, counter, "unlink sem");
1815+
n_opened_sems = remove_counter(counter);
1816+
puts("unlink sem, removed");
1817+
}
1818+
RELEASE_GLOCK;
1819+
if (!n_opened_sems) {
1820+
delete_glock();
1821+
}
1822+
}
1823+
*/
1824+
}
17961825
#endif /* HAVE_BROKEN_SEM_GETVALUE */
17971826

17981827
Py_RETURN_NONE;

Modules/_multiprocessing/semaphore_macosx.h

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,10 @@ typedef struct {
3232

3333
typedef struct {
3434
char sem_name[SIZE_SEM_NAME]; // Name of semaphore.
35-
int internal_value; // Internal value of semaphore, update on each acquire/release.
36-
int n_instances; // Number of SemLockObject linked to this CounterObject.
37-
time_t ctimestamp; // Created timestamp (debug log).
35+
short internal_value; // Internal value of semaphore, update on each acquire/release.
36+
short n_instances; // Number of SemLockObject linked to this CounterObject.
37+
short unlink; // Flag to know if this CounterObject is unlink or not.
38+
time_t ctimestamp; // Created timestamp (debug log).
3839
} CounterObject;
3940

4041
/*
@@ -77,15 +78,15 @@ struct _CountersWorkaround{
7778
m); \
7879
} while(0);
7980

80-
#define LOG_GLOCK(m) fprintf(stderr, "%s %s: %03d\n", m, __func__, __LINE__)
81-
#define LOG_LOCK(m, h) fprintf(stderr, "%s(%02lX) %s: %03d\n", m, (unsigned long)h, __func__, __LINE__)
81+
#define LOG_GLOCK(m) 1 // fprintf(stderr, "%s %s: %03d\n", m, __func__, __LINE__)
82+
#define LOG_LOCK(m, h) 1 // fprintf(stderr, "%s(%02lX) %s: %03d\n", m, (unsigned long)h, __func__, __LINE__)
8283
#else
8384
#define DEBUG_PID_FUNC(n, h, c, m) 1
8485
#define LOG_GLOCK(m) 1
8586
#define LOG_LOCK(m, h) 1
8687
#endif
8788

88-
#define EXIST_GLOCK (LOG_GLOCK("EXIST_LOCK") > 0 && exist_lock(sem) == 0)
89+
#define EXIST_GLOCK (LOG_GLOCK("EXIST_GLOCK") > 0 && exist_lock(shm_semlock_counters.handle_glock) == 1)
8990
#define ACQUIRE_GLOCK (LOG_GLOCK("ACQ_GLOCK") > 0 && acquire_lock(shm_semlock_counters.handle_glock) == 0)
9091
#define RELEASE_GLOCK (LOG_GLOCK("\tREL_GLOCK") > 0 && release_lock(shm_semlock_counters.handle_glock) == 0)
9192
#define ACQUIRE_COUNTER_MUTEX(h) (LOG_LOCK("acq", h) && acquire_lock((h)) == 0)

0 commit comments

Comments
 (0)