#include <mono/io-layer/shared.h>
#include <mono/io-layer/collection.h>
#include <mono/io-layer/process-private.h>
+#include <mono/io-layer/critical-section-private.h>
#undef DEBUG
#undef DEBUG_REFS
pthread_cond_t _wapi_global_signal_cond;
int _wapi_sem_id;
+gboolean _wapi_has_shut_down = FALSE;
/* Use this instead of getpid(), to cope with linuxthreads. It's a
* function rather than a variable lookup because we need to get at
if (_WAPI_SHARED_HANDLE (type)) {
gpointer handle = GINT_TO_POINTER (i*_WAPI_HANDLE_INITIAL_COUNT+j);
+ if (type == WAPI_HANDLE_THREAD) {
+ /* Special-case thread handles
+ * because they need extra
+ * cleanup. This also avoids
+ * a race condition between
+ * the application exit and
+ * the finalizer thread - if
+ * it finishes up between now
+ * and actual app termination
+ * it will find all its handle
+ * details have been blown
+ * away, so this sets those
+ * anyway.
+ */
+ _wapi_thread_set_termination_details (handle, 0);
+ }
+
for(k = handle_data->ref; k > 0; k--) {
#ifdef DEBUG
g_message ("%s: unreffing %s handle %p", __func__, _wapi_handle_typename[type], handle);
}
_wapi_shm_semaphores_remove ();
+
+ mono_mutex_destroy(&_wapi_global_signal_mutex);
+ pthread_cond_destroy(&_wapi_global_signal_cond);
+}
+
+void _wapi_cleanup ()
+{
+ g_assert (_wapi_has_shut_down == FALSE);
+
+ _wapi_has_shut_down = TRUE;
+
+ _wapi_critical_section_cleanup ();
+ _wapi_error_cleanup ();
+ _wapi_thread_cleanup ();
}
static mono_once_t shared_init_once = MONO_ONCE_INIT;
WapiHandleType type,
gpointer handle_specific)
{
+ g_assert (_wapi_has_shut_down == FALSE);
+
handle->type = type;
handle->timestamp = (guint32)(time (NULL) & 0xFFFFFFFF);
handle->signalled = FALSE;
{
int thr_ret;
+ g_assert (_wapi_has_shut_down == FALSE);
+
handle->type = type;
handle->signalled = FALSE;
handle->ref = 1;
static guint32 last = 1;
int thr_ret;
+ g_assert (_wapi_has_shut_down == FALSE);
+
/* Leave the first slot empty as a guard */
again:
/* FIXME: expandable array */
static guint32 last = 0;
gboolean retry = FALSE;
+ g_assert (_wapi_has_shut_down == FALSE);
+
/* A linear scan should be fast enough. Start from the last
* allocation, assuming that handles are allocated more often
* than they're freed. Leave the space reserved for file
gpointer handle;
int thr_ret;
+ g_assert (_wapi_has_shut_down == FALSE);
+
mono_once (&shared_init_once, shared_init);
#ifdef DEBUG
struct _WapiHandleShared *shared;
guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
+ g_assert (_wapi_has_shut_down == FALSE);
+
mono_once (&shared_init_once, shared_init);
#ifdef DEBUG
shared = &_wapi_shared_layout->handles[offset];
if (timestamp) {
/* Bump up the timestamp for this offset */
- InterlockedExchange (&shared->timestamp, now);
+ InterlockedExchange ((gint32 *)&shared->timestamp, now);
}
pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
handle = GUINT_TO_POINTER (handle_idx);
_WAPI_PRIVATE_HANDLES(handle_idx).u.shared.offset = offset;
- InterlockedIncrement (&shared->handle_refs);
+ InterlockedIncrement ((gint32 *)&shared->handle_refs);
#ifdef DEBUG
g_message ("%s: Allocated new handle %p referencing 0x%x (shared refs %d)", __func__, handle, offset, shared->handle_refs);
struct _WapiHandleUnshared *handle;
int thr_ret;
+ g_assert (_wapi_has_shut_down == FALSE);
+
mono_once (&shared_init_once, shared_init);
#ifdef DEBUG
if (shared->type == type) {
guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
- InterlockedExchange (&shared->timestamp, now);
+ InterlockedExchange ((gint32 *)&shared->timestamp, now);
found = TRUE;
handle_data = &_WAPI_PRIVATE_HANDLES(GPOINTER_TO_UINT(ret));
handle_data = &_WAPI_PRIVATE_HANDLES(idx);
- InterlockedIncrement (&handle_data->ref);
+ InterlockedIncrement ((gint32 *)&handle_data->ref);
/* It's possible for processes to exit before getting around
* to updating timestamps in the collection thread, so if a
if (_WAPI_SHARED_HANDLE(handle_data->type)) {
struct _WapiHandleShared *shared_data = &_wapi_shared_layout->handles[handle_data->u.shared.offset];
- InterlockedExchange (&shared_data->timestamp, now);
+ InterlockedExchange ((gint32 *)&shared_data->timestamp, now);
}
#ifdef DEBUG_REFS
* could lock a mutex, but I'm not sure that allowing a handle
* reference to reach 0 isn't an application bug anyway.
*/
- destroy = (InterlockedDecrement (&_WAPI_PRIVATE_HANDLES(idx).ref) ==0);
+ destroy = (InterlockedDecrement ((gint32 *)&_WAPI_PRIVATE_HANDLES(idx).ref) ==0);
#ifdef DEBUG_REFS
g_message ("%s: %s handle %p ref now %d (destroy %s)", __func__,
*/
gboolean CloseHandle(gpointer handle)
{
+ if (handle == NULL) {
+ /* Problem: because we map file descriptors to the
+ * same-numbered handle we can't tell the difference
+ * between a bogus handle and the handle to stdin.
+ * Assume that it's the console handle if that handle
+ * exists...
+ */
+ if (_WAPI_PRIVATE_HANDLES (0).type != WAPI_HANDLE_CONSOLE) {
+ SetLastError (ERROR_INVALID_PARAMETER);
+ return(FALSE);
+ }
+ }
+ if (handle == _WAPI_HANDLE_INVALID){
+ SetLastError (ERROR_INVALID_PARAMETER);
+ return(FALSE);
+ }
+
_wapi_handle_unref (handle);
return(TRUE);
}
}
-static int timedwait_signal_poll_cond (pthread_cond_t *cond, mono_mutex_t *mutex, struct timespec *timeout)
+static int timedwait_signal_poll_cond (pthread_cond_t *cond, mono_mutex_t *mutex, struct timespec *timeout, gboolean alertable)
{
struct timespec fake_timeout;
int ret;
-
- _wapi_calc_timeout (&fake_timeout, 100);
-
- if (timeout != NULL && ((fake_timeout.tv_sec > timeout->tv_sec) ||
- (fake_timeout.tv_sec == timeout->tv_sec &&
- fake_timeout.tv_nsec > timeout->tv_nsec))) {
- /* Real timeout is less than 100ms time */
- ret=mono_cond_timedwait (cond, mutex, timeout);
+
+ if (!alertable) {
+ if (timeout)
+ ret=mono_cond_timedwait (cond, mutex, timeout);
+ else
+ ret=mono_cond_wait (cond, mutex);
} else {
- ret=mono_cond_timedwait (cond, mutex, &fake_timeout);
+ _wapi_calc_timeout (&fake_timeout, 100);
+
+ if (timeout != NULL && ((fake_timeout.tv_sec > timeout->tv_sec) ||
+ (fake_timeout.tv_sec == timeout->tv_sec &&
+ fake_timeout.tv_nsec > timeout->tv_nsec))) {
+ /* Real timeout is less than 100ms time */
+ ret=mono_cond_timedwait (cond, mutex, timeout);
+ } else {
+ ret=mono_cond_timedwait (cond, mutex, &fake_timeout);
- /* Mask the fake timeout, this will cause
- * another poll if the cond was not really signaled
- */
- if (ret==ETIMEDOUT) {
- ret=0;
+ /* Mask the fake timeout, this will cause
+ * another poll if the cond was not really signaled
+ */
+ if (ret==ETIMEDOUT) {
+ ret=0;
+ }
}
}
int _wapi_handle_wait_signal (void)
{
- return timedwait_signal_poll_cond (&_wapi_global_signal_cond, &_wapi_global_signal_mutex, NULL);
+ return timedwait_signal_poll_cond (&_wapi_global_signal_cond, &_wapi_global_signal_mutex, NULL, TRUE);
}
int _wapi_handle_timedwait_signal (struct timespec *timeout)
{
- return timedwait_signal_poll_cond (&_wapi_global_signal_cond, &_wapi_global_signal_mutex, timeout);
+ return timedwait_signal_poll_cond (&_wapi_global_signal_cond, &_wapi_global_signal_mutex, timeout, TRUE);
}
-int _wapi_handle_wait_signal_handle (gpointer handle)
+int _wapi_handle_wait_signal_handle (gpointer handle, gboolean alertable)
{
#ifdef DEBUG
g_message ("%s: waiting for %p", __func__, handle);
#endif
- return _wapi_handle_timedwait_signal_handle (handle, NULL);
+ return _wapi_handle_timedwait_signal_handle (handle, NULL, alertable);
}
int _wapi_handle_timedwait_signal_handle (gpointer handle,
- struct timespec *timeout)
+ struct timespec *timeout, gboolean alertable)
{
#ifdef DEBUG
g_message ("%s: waiting for %p (type %s)", __func__, handle,
} else {
guint32 idx = GPOINTER_TO_UINT(handle);
- return timedwait_signal_poll_cond (&_WAPI_PRIVATE_HANDLES(idx).signal_cond, &_WAPI_PRIVATE_HANDLES(idx).signal_mutex, timeout);
+ return timedwait_signal_poll_cond (&_WAPI_PRIVATE_HANDLES(idx).signal_cond, &_WAPI_PRIVATE_HANDLES(idx).signal_mutex, timeout, alertable);
}
}
* This makes the increment atomic wrt
* collections
*/
- InterlockedIncrement (&file_share->handle_refs);
+ InterlockedIncrement ((gint32 *)&file_share->handle_refs);
exists = TRUE;
break;
}
if (*share_info != NULL) {
- InterlockedExchange (&(*share_info)->timestamp, now);
+ InterlockedExchange ((gint32 *)&(*share_info)->timestamp, now);
}
thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
g_message ("%s: (%d) Updating timestamp of handle 0x%x", __func__, _wapi_getpid (), handle->u.shared.offset);
#endif
- InterlockedExchange (&shared_data->timestamp,
- now);
+ InterlockedExchange ((gint32 *)&shared_data->timestamp, now);
} else if (handle->type == WAPI_HANDLE_FILE) {
struct _WapiHandle_file *file_handle = &handle->u.file;
g_message ("%s: (%d) Inc refs on fileshare 0x%x", __func__, _wapi_getpid (), (file_handle->share_info - &_wapi_fileshare_layout->share_info[0]) / sizeof(struct _WapiFileShare));
#endif
- InterlockedExchange (&file_handle->share_info->timestamp, now);
+ InterlockedExchange ((gint32 *)&file_handle->share_info->timestamp, now);
}
}
}