#include <pthread.h>
#include <errno.h>
#include <unistd.h>
+#ifdef HAVE_SIGNAL_H
#include <signal.h>
+#endif
#include <string.h>
#include <sys/types.h>
#ifdef HAVE_SYS_SOCKET_H
# include <dirent.h>
#endif
#include <sys/stat.h>
+#ifdef HAVE_SYS_RESOURCE_H
+# include <sys/resource.h>
+#endif
#include <mono/io-layer/wapi.h>
#include <mono/io-layer/wapi-private.h>
#include <mono/io-layer/process-private.h>
#include <mono/utils/mono-mutex.h>
+#include <mono/utils/mono-proclib.h>
+#include <mono/utils/mono-threads.h>
#undef DEBUG_REFS
#if 0
g_free (_wapi_private_handles [i]);
}
+int
+wapi_getdtablesize (void)
+{
+ return eg_getdtablesize ();
+}
+
/*
* wapi_init:
*
{
g_assert ((sizeof (handle_ops) / sizeof (handle_ops[0]))
== WAPI_HANDLE_COUNT);
-
- _wapi_fd_reserve = getdtablesize();
+
+ _wapi_fd_reserve = wapi_getdtablesize ();
/* This is needed by the code in _wapi_handle_new_internal */
_wapi_fd_reserve = (_wapi_fd_reserve + (_WAPI_HANDLE_INITIAL_COUNT - 1)) & ~(_WAPI_HANDLE_INITIAL_COUNT - 1);
_wapi_global_signal_cond = &_WAPI_PRIVATE_HANDLES (GPOINTER_TO_UINT (_wapi_global_signal_handle)).signal_cond;
_wapi_global_signal_mutex = &_WAPI_PRIVATE_HANDLES (GPOINTER_TO_UINT (_wapi_global_signal_handle)).signal_mutex;
-
- /* Using g_atexit here instead of an explicit function call in
- * a cleanup routine lets us cope when a third-party library
- * calls exit (eg if an X client loses the connection to its
- * server.)
- */
- g_atexit (handle_cleanup);
+ wapi_processes_init ();
}
void
_wapi_error_cleanup ();
_wapi_thread_cleanup ();
wapi_processes_cleanup ();
+ handle_cleanup ();
}
static void _wapi_handle_init_shared (struct _WapiHandleShared *handle,
int ret;
if (!alertable) {
+ /*
+ * pthread_cond_(timed)wait() can return 0 even if the condition was not
+ * signalled. This happens at least on Darwin. We surface this, i.e., we
+ * get spurious wake-ups.
+ *
+ * http://pubs.opengroup.org/onlinepubs/007908775/xsh/pthread_cond_wait.html
+ */
if (timeout)
ret=mono_cond_timedwait (cond, mutex, timeout);
else
return(ret);
}
-int _wapi_handle_wait_signal (gboolean poll)
+int
+_wapi_handle_timedwait_signal (struct timespec *timeout, gboolean poll, gboolean *alerted)
{
- return _wapi_handle_timedwait_signal_handle (_wapi_global_signal_handle, NULL, TRUE, poll);
+ return _wapi_handle_timedwait_signal_handle (_wapi_global_signal_handle, timeout, TRUE, poll, alerted);
}
-int _wapi_handle_timedwait_signal (struct timespec *timeout, gboolean poll)
+static void
+signal_handle_and_unref (gpointer handle)
{
- return _wapi_handle_timedwait_signal_handle (_wapi_global_signal_handle, timeout, TRUE, poll);
-}
+ pthread_cond_t *cond;
+ mono_mutex_t *mutex;
+ guint32 idx;
-int _wapi_handle_wait_signal_handle (gpointer handle, gboolean alertable)
-{
- DEBUG ("%s: waiting for %p", __func__, handle);
-
- return _wapi_handle_timedwait_signal_handle (handle, NULL, alertable, FALSE);
+ g_assert (handle);
+
+ /* If we reach here, then interrupt token is set to the flag value, which
+ * means that the target thread is either
+ * - before the first CAS in timedwait, which means it won't enter the wait.
+ * - it is after the first CAS, so it is already waiting, or it will enter
+ * the wait, and it will be interrupted by the broadcast. */
+ idx = GPOINTER_TO_UINT (handle);
+ cond = &_WAPI_PRIVATE_HANDLES (idx).signal_cond;
+ mutex = &_WAPI_PRIVATE_HANDLES (idx).signal_mutex;
+
+ mono_mutex_lock (mutex);
+ mono_cond_broadcast (cond);
+ mono_mutex_unlock (mutex);
+
+ _wapi_handle_unref (handle);
}
-int _wapi_handle_timedwait_signal_handle (gpointer handle,
- struct timespec *timeout, gboolean alertable, gboolean poll)
+int
+_wapi_handle_timedwait_signal_handle (gpointer handle, struct timespec *timeout,
+ gboolean alertable, gboolean poll, gboolean *alerted)
{
DEBUG ("%s: waiting for %p (type %s)", __func__, handle,
_wapi_handle_typename[_wapi_handle_type (handle)]);
-
+
+ if (alertable)
+ g_assert (alerted);
+
+ if (alerted)
+ *alerted = FALSE;
+
if (_WAPI_SHARED_HANDLE (_wapi_handle_type (handle))) {
if (WAPI_SHARED_HANDLE_DATA(handle).signalled == TRUE) {
return (0);
pthread_cond_t *cond;
mono_mutex_t *mutex;
- if (alertable && !wapi_thread_set_wait_handle (handle))
- return 0;
+ if (alertable) {
+ mono_thread_info_install_interrupt (signal_handle_and_unref, handle, alerted);
+ if (*alerted)
+ return 0;
+ _wapi_handle_ref (handle);
+ }
cond = &_WAPI_PRIVATE_HANDLES (idx).signal_cond;
mutex = &_WAPI_PRIVATE_HANDLES (idx).signal_mutex;
res = mono_cond_wait (cond, mutex);
}
- if (alertable)
- wapi_thread_clear_wait_handle (handle);
+ if (alertable) {
+ mono_thread_info_uninstall_interrupt (alerted);
+ if (!*alerted) {
+ /* if it is alerted, then the handle is unref in the interrupt callback */
+ _wapi_handle_unref (handle);
+ }
+ }
return res;
}
return s->inode;
}
-gboolean _wapi_handle_get_or_set_share (dev_t device, ino_t inode,
+gboolean _wapi_handle_get_or_set_share (guint64 device, guint64 inode,
guint32 new_sharemode,
guint32 new_access,
guint32 *old_sharemode,
{
#if defined(__native_client__)
g_assert_not_reached ();
-#else
+#elif defined(HAVE_KILL)
if (kill (share_info->opened_by_pid, 0) == -1 &&
(errno == ESRCH ||
errno == EPERM)) {
void _wapi_handle_check_share (struct _WapiFileShare *share_info, int fd)
{
gboolean found = FALSE, proc_fds = FALSE;
- pid_t self = _wapi_getpid ();
- int pid;
int thr_ret, i;
/* Prevents entries from expiring under us if we remove this
}
}
- for (i = 0; i < _WAPI_HANDLE_INITIAL_COUNT; i++) {
- struct _WapiHandleShared *shared;
- struct _WapiHandle_process *process_handle;
-
- shared = &_wapi_shared_layout->handles[i];
-
- if (shared->type == WAPI_HANDLE_PROCESS) {
- DIR *fd_dir;
- struct dirent *fd_entry;
- char subdir[_POSIX_PATH_MAX];
-
- process_handle = &shared->u.process;
- pid = process_handle->id;
-
- /* Look in /proc/<pid>/fd/ but ignore
- * /proc/<our pid>/fd/<fd>, as we have the
- * file open too
- */
- g_snprintf (subdir, _POSIX_PATH_MAX, "/proc/%d/fd",
- pid);
-
- fd_dir = opendir (subdir);
- if (fd_dir == NULL) {
- continue;
- }
-
- DEBUG ("%s: Looking in %s", __func__, subdir);
-
- proc_fds = TRUE;
-
- while ((fd_entry = readdir (fd_dir)) != NULL) {
- char path[_POSIX_PATH_MAX];
- struct stat link_stat;
-
- if (!strcmp (fd_entry->d_name, ".") ||
- !strcmp (fd_entry->d_name, "..") ||
- (pid == self &&
- fd == atoi (fd_entry->d_name))) {
- continue;
- }
-
- g_snprintf (path, _POSIX_PATH_MAX,
- "/proc/%d/fd/%s", pid,
- fd_entry->d_name);
-
- stat (path, &link_stat);
- if (link_stat.st_dev == share_info->device &&
- link_stat.st_ino == share_info->inode) {
- DEBUG ("%s: Found it at %s",
- __func__, path);
-
- found = TRUE;
- }
- }
-
- closedir (fd_dir);
- }
- }
-
if (proc_fds == FALSE) {
_wapi_handle_check_share_by_pid (share_info);
} else if (found == FALSE) {