value lwt_unix_recv_notifications() { int ret, i, current_index; value result; #if !defined(LWT_ON_WINDOWS) sigset_t new_mask; sigset_t old_mask; int error; sigfillset(&new_mask); pthread_sigmask(SIG_SETMASK, &new_mask, &old_mask); #else DWORD error; #endif lwt_unix_mutex_lock(¬ification_mutex); /* Receive the signal. */ ret = notification_recv(); #if defined(LWT_ON_WINDOWS) if (ret == SOCKET_ERROR) { error = WSAGetLastError(); lwt_unix_mutex_unlock(¬ification_mutex); win32_maperr(error); uerror("recv_notifications", Nothing); } #else if (ret < 0) { error = errno; lwt_unix_mutex_unlock(¬ification_mutex); pthread_sigmask(SIG_SETMASK, &old_mask, NULL); unix_error(error, "recv_notifications", Nothing); } #endif do { /* release the mutex while calling caml_alloc, which may call gc and switch the thread, resulting in a classical deadlock, when thread in question tries another send */ current_index = notification_index; lwt_unix_mutex_unlock(¬ification_mutex); result = caml_alloc_tuple(current_index); lwt_unix_mutex_lock(¬ification_mutex); /* check that no new notifications appeared meanwhile (rare) */ } while (current_index != notification_index); /* Read all pending notifications. */ for (i = 0; i < notification_index; i++) Field(result, i) = Val_long(notifications[i]); /* Reset the index. */ notification_index = 0; lwt_unix_mutex_unlock(¬ification_mutex); #if !defined(LWT_ON_WINDOWS) pthread_sigmask(SIG_SETMASK, &old_mask, NULL); #endif return result; }
void lwt_unix_send_notification(intnat id) { int ret; #if !defined(LWT_ON_WINDOWS) sigset_t new_mask; sigset_t old_mask; int error; sigfillset(&new_mask); pthread_sigmask(SIG_SETMASK, &new_mask, &old_mask); #else DWORD error; #endif lwt_unix_mutex_lock(¬ification_mutex); if (notification_index > 0) { /* There is already a pending notification in the buffer, no need to signal the main thread. */ if (notification_index == notification_count) resize_notifications(); notifications[notification_index++] = id; } else { /* There is none, notify the main thread. */ notifications[notification_index++] = id; ret = notification_send(); #if defined(LWT_ON_WINDOWS) if (ret == SOCKET_ERROR) { error = WSAGetLastError(); if (error != WSANOTINITIALISED) { lwt_unix_mutex_unlock(¬ification_mutex); win32_maperr(error); uerror("send_notification", Nothing); } /* else we're probably shutting down, so ignore the error */ } #else if (ret < 0) { error = errno; lwt_unix_mutex_unlock(¬ification_mutex); pthread_sigmask(SIG_SETMASK, &old_mask, NULL); unix_error(error, "send_notification", Nothing); } #endif } lwt_unix_mutex_unlock(¬ification_mutex); #if !defined(LWT_ON_WINDOWS) pthread_sigmask(SIG_SETMASK, &old_mask, NULL); #endif }
value lwt_unix_recv_notifications() { int ret, i; value result; #if !defined(LWT_ON_WINDOWS) sigset_t new_mask; sigset_t old_mask; int error; sigfillset(&new_mask); pthread_sigmask(SIG_SETMASK, &new_mask, &old_mask); #else DWORD error; #endif lwt_unix_mutex_lock(¬ification_mutex); /* Receive the signal. */ ret = notification_recv(); #if defined(LWT_ON_WINDOWS) if (ret == SOCKET_ERROR) { error = WSAGetLastError(); lwt_unix_mutex_unlock(¬ification_mutex); win32_maperr(error); uerror("recv_notifications", Nothing); } #else if (ret < 0) { error = errno; lwt_unix_mutex_unlock(¬ification_mutex); pthread_sigmask(SIG_SETMASK, &old_mask, NULL); unix_error(error, "recv_notifications", Nothing); } #endif /* Read all pending notifications. */ result = caml_alloc_tuple(notification_index); for (i = 0; i < notification_index; i++) Field(result, i) = Val_long(notifications[i]); /* Reset the index. */ notification_index = 0; lwt_unix_mutex_unlock(¬ification_mutex); #if !defined(LWT_ON_WINDOWS) pthread_sigmask(SIG_SETMASK, &old_mask, NULL); #endif return result; }
/* Execute the given job. */ static void execute_job(lwt_unix_job job) { DEBUG("executing the job"); lwt_unix_mutex_lock(&job->mutex); /* Mark the job as running. */ job->state = LWT_UNIX_JOB_STATE_RUNNING; /* Set the thread of the job. */ job->thread = lwt_unix_thread_self(); lwt_unix_mutex_unlock(&job->mutex); /* Execute the job. */ job->worker(job); DEBUG("job done"); lwt_unix_mutex_lock(&job->mutex); DEBUG("marking the job has done"); /* Job is done. If the main thread stopped until now, asynchronous notification is not necessary. */ job->state = LWT_UNIX_JOB_STATE_DONE; /* Send a notification if the main thread continued its execution before the job terminated. */ if (job->fast == 0) { lwt_unix_mutex_unlock(&job->mutex); DEBUG("notifying the main thread"); lwt_unix_send_notification(job->notification_id); } else { lwt_unix_mutex_unlock(&job->mutex); DEBUG("not notifying the main thread"); } }