#include "fdhandle.h" #include "utils/mono-lazy-init.h" #include "utils/mono-coop-mutex.h" static GHashTable *fds; static MonoCoopMutex fds_mutex; static MonoFDHandleCallback fds_callback[MONO_FDTYPE_COUNT]; static mono_lazy_init_t fds_init = MONO_LAZY_INIT_STATUS_NOT_INITIALIZED; static const gchar *types_str[] = { "File", "Console", "Pipe", "Socket", NULL }; static void fds_remove (gpointer data) { MonoFDHandle* fdhandle; fdhandle = (MonoFDHandle*) data; g_assert (fdhandle); g_assert (fds_callback [fdhandle->type].close); fds_callback [fdhandle->type].close (fdhandle); mono_refcount_dec (fdhandle); } static void initialize (void) { fds = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, fds_remove); mono_coop_mutex_init (&fds_mutex); } void mono_fdhandle_register (MonoFDType type, MonoFDHandleCallback *callback) { mono_lazy_initialize (&fds_init, initialize); memcpy (&fds_callback [type], callback, sizeof (MonoFDHandleCallback)); } static void fdhandle_destroy (gpointer data) { MonoFDHandle* fdhandle; fdhandle = (MonoFDHandle*) data; g_assert (fdhandle); g_assert (fds_callback [fdhandle->type].destroy); fds_callback [fdhandle->type].destroy (fdhandle); } void mono_fdhandle_init (MonoFDHandle *fdhandle, MonoFDType type, gint fd) { mono_refcount_init (fdhandle, fdhandle_destroy); fdhandle->type = type; fdhandle->fd = fd; } void mono_fdhandle_insert (MonoFDHandle *fdhandle) { mono_coop_mutex_lock (&fds_mutex); if (g_hash_table_lookup_extended (fds, GINT_TO_POINTER(fdhandle->fd), NULL, NULL)) g_error("%s: duplicate %s fd %d", __func__, types_str [fdhandle->type], fdhandle->fd); g_hash_table_insert (fds, GINT_TO_POINTER(fdhandle->fd), fdhandle); mono_coop_mutex_unlock (&fds_mutex); } gboolean mono_fdhandle_try_insert (MonoFDHandle *fdhandle) { mono_coop_mutex_lock (&fds_mutex); if (g_hash_table_lookup_extended (fds, GINT_TO_POINTER(fdhandle->fd), NULL, NULL)) { /* we raced between 2 invocations of mono_fdhandle_try_insert */ mono_coop_mutex_unlock (&fds_mutex); return FALSE; } g_hash_table_insert (fds, GINT_TO_POINTER(fdhandle->fd), fdhandle); mono_coop_mutex_unlock (&fds_mutex); return TRUE; } gboolean mono_fdhandle_lookup_and_ref (gint fd, MonoFDHandle **fdhandle) { mono_coop_mutex_lock (&fds_mutex); if (!g_hash_table_lookup_extended (fds, GINT_TO_POINTER(fd), NULL, (gpointer*) fdhandle)) { mono_coop_mutex_unlock (&fds_mutex); return FALSE; } mono_refcount_inc (*fdhandle); mono_coop_mutex_unlock (&fds_mutex); return TRUE; } void mono_fdhandle_unref (MonoFDHandle *fdhandle) { mono_refcount_dec (fdhandle); } gboolean mono_fdhandle_close (gint fd) { MonoFDHandle *fdhandle; gboolean removed; mono_coop_mutex_lock (&fds_mutex); if (!g_hash_table_lookup_extended (fds, GINT_TO_POINTER(fd), NULL, (gpointer*) &fdhandle)) { mono_coop_mutex_unlock (&fds_mutex); return FALSE; } removed = g_hash_table_remove (fds, GINT_TO_POINTER(fdhandle->fd)); g_assert (removed); mono_coop_mutex_unlock (&fds_mutex); return TRUE; }