Skip to content

Commit

Permalink
Unix.fork: reinitialize IO channel mutexes in the child instead of de…
Browse files Browse the repository at this point in the history
…stroying them

Some of these mutexes may be locked, so both destroying and
reinitializing are undefined behaviors.  However, destroying can cause
fatal errors in the C pthread library (ocaml#12636), while reinitializing
should not.

Fixes: ocaml#12636
  • Loading branch information
xavierleroy committed Oct 26, 2023
1 parent b1fcbaa commit ea90edc
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 13 deletions.
26 changes: 18 additions & 8 deletions otherlibs/systhreads/st_posix.h
Original file line number Diff line number Diff line change
Expand Up @@ -197,31 +197,41 @@ Caml_inline void st_thread_yield(st_masterlock * m)

typedef pthread_mutex_t * st_mutex;

static int st_mutex_create(st_mutex * res)
static int st_mutex_init(st_mutex m)
{
int rc;
pthread_mutexattr_t attr;
st_mutex m;

rc = pthread_mutexattr_init(&attr);
if (rc != 0) goto error1;
rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
if (rc != 0) goto error2;
m = caml_stat_alloc_noexc(sizeof(pthread_mutex_t));
if (m == NULL) { rc = ENOMEM; goto error2; }
rc = pthread_mutex_init(m, &attr);
if (rc != 0) goto error3;
if (rc != 0) goto error2;
pthread_mutexattr_destroy(&attr);
*res = m;
return 0;
error3:
caml_stat_free(m);
error2:
pthread_mutexattr_destroy(&attr);
error1:
return rc;
}

static int st_mutex_create(st_mutex * res)
{
int rc;
st_mutex m;

m = caml_stat_alloc_noexc(sizeof(pthread_mutex_t));
if (m == NULL) { return ENOMEM; }
rc = st_mutex_init(m);
if (rc != 0) {
caml_stat_free(m);
return rc;
}
*res = m;
return 0;
}

static int st_mutex_destroy(st_mutex m)
{
int rc;
Expand Down
7 changes: 2 additions & 5 deletions otherlibs/systhreads/st_stubs.c
Original file line number Diff line number Diff line change
Expand Up @@ -417,14 +417,11 @@ static void caml_thread_reinitialize(void)
/* Tick thread is not currently running in child process, will be
re-created at next Thread.create */
caml_tick_thread_running = 0;
/* Destroy all IO mutexes; will be reinitialized on demand */
/* Reinitialize all IO mutexes */
for (chan = caml_all_opened_channels;
chan != NULL;
chan = chan->next) {
if (chan->mutex != NULL) {
st_mutex_destroy(chan->mutex);
chan->mutex = NULL;
}
if (chan->mutex != NULL) st_mutex_init(chan->mutex);
}
}

Expand Down
6 changes: 6 additions & 0 deletions otherlibs/systhreads/st_win32.h
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,12 @@ static DWORD st_mutex_destroy(st_mutex m)
return 0;
}

/* Unused under Windows because there is no fork() */
static DWORD st_mutex_init(st_mutex m)
{
return 0;
}

/* Error codes with the 29th bit set are reserved for the application */

#define MUTEX_DEADLOCK (1<<29 | 1)
Expand Down

0 comments on commit ea90edc

Please sign in to comment.