1 
2 #include "fdhandle.h"
3 #include "utils/mono-lazy-init.h"
4 #include "utils/mono-coop-mutex.h"
5 
6 static GHashTable *fds;
7 static MonoCoopMutex fds_mutex;
8 static MonoFDHandleCallback fds_callback[MONO_FDTYPE_COUNT];
9 static mono_lazy_init_t fds_init = MONO_LAZY_INIT_STATUS_NOT_INITIALIZED;
10 
11 static const gchar *types_str[] = {
12 	"File",
13 	"Console",
14 	"Pipe",
15 	"Socket",
16 	NULL
17 };
18 
19 static void
fds_remove(gpointer data)20 fds_remove (gpointer data)
21 {
22 	MonoFDHandle* fdhandle;
23 
24 	fdhandle = (MonoFDHandle*) data;
25 	g_assert (fdhandle);
26 
27 	g_assert (fds_callback [fdhandle->type].close);
28 	fds_callback [fdhandle->type].close (fdhandle);
29 
30 	mono_refcount_dec (fdhandle);
31 }
32 
33 static void
initialize(void)34 initialize (void)
35 {
36 	fds = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, fds_remove);
37 	mono_coop_mutex_init (&fds_mutex);
38 }
39 
40 void
mono_fdhandle_register(MonoFDType type,MonoFDHandleCallback * callback)41 mono_fdhandle_register (MonoFDType type, MonoFDHandleCallback *callback)
42 {
43 	mono_lazy_initialize (&fds_init, initialize);
44 	memcpy (&fds_callback [type], callback, sizeof (MonoFDHandleCallback));
45 }
46 
47 static void
fdhandle_destroy(gpointer data)48 fdhandle_destroy (gpointer data)
49 {
50 	MonoFDHandle* fdhandle;
51 
52 	fdhandle = (MonoFDHandle*) data;
53 	g_assert (fdhandle);
54 
55 	g_assert (fds_callback [fdhandle->type].destroy);
56 	fds_callback [fdhandle->type].destroy (fdhandle);
57 }
58 
59 void
mono_fdhandle_init(MonoFDHandle * fdhandle,MonoFDType type,gint fd)60 mono_fdhandle_init (MonoFDHandle *fdhandle, MonoFDType type, gint fd)
61 {
62 	mono_refcount_init (fdhandle, fdhandle_destroy);
63 	fdhandle->type = type;
64 	fdhandle->fd = fd;
65 }
66 
67 void
mono_fdhandle_insert(MonoFDHandle * fdhandle)68 mono_fdhandle_insert (MonoFDHandle *fdhandle)
69 {
70 	mono_coop_mutex_lock (&fds_mutex);
71 
72 	if (g_hash_table_lookup_extended (fds, GINT_TO_POINTER(fdhandle->fd), NULL, NULL))
73 		g_error("%s: duplicate %s fd %d", __func__, types_str [fdhandle->type], fdhandle->fd);
74 
75 	g_hash_table_insert (fds, GINT_TO_POINTER(fdhandle->fd), fdhandle);
76 
77 	mono_coop_mutex_unlock (&fds_mutex);
78 }
79 
80 gboolean
mono_fdhandle_try_insert(MonoFDHandle * fdhandle)81 mono_fdhandle_try_insert (MonoFDHandle *fdhandle)
82 {
83 	mono_coop_mutex_lock (&fds_mutex);
84 
85 	if (g_hash_table_lookup_extended (fds, GINT_TO_POINTER(fdhandle->fd), NULL, NULL)) {
86 		/* we raced between 2 invocations of mono_fdhandle_try_insert */
87 		mono_coop_mutex_unlock (&fds_mutex);
88 
89 		return FALSE;
90 	}
91 
92 	g_hash_table_insert (fds, GINT_TO_POINTER(fdhandle->fd), fdhandle);
93 
94 	mono_coop_mutex_unlock (&fds_mutex);
95 
96 	return TRUE;
97 }
98 
99 gboolean
mono_fdhandle_lookup_and_ref(gint fd,MonoFDHandle ** fdhandle)100 mono_fdhandle_lookup_and_ref (gint fd, MonoFDHandle **fdhandle)
101 {
102 	mono_coop_mutex_lock (&fds_mutex);
103 
104 	if (!g_hash_table_lookup_extended (fds, GINT_TO_POINTER(fd), NULL, (gpointer*) fdhandle)) {
105 		mono_coop_mutex_unlock (&fds_mutex);
106 		return FALSE;
107 	}
108 
109 	mono_refcount_inc (*fdhandle);
110 
111 	mono_coop_mutex_unlock (&fds_mutex);
112 
113 	return TRUE;
114 }
115 
116 void
mono_fdhandle_unref(MonoFDHandle * fdhandle)117 mono_fdhandle_unref (MonoFDHandle *fdhandle)
118 {
119 	mono_refcount_dec (fdhandle);
120 }
121 
122 gboolean
mono_fdhandle_close(gint fd)123 mono_fdhandle_close (gint fd)
124 {
125 	MonoFDHandle *fdhandle;
126 	gboolean removed;
127 
128 	mono_coop_mutex_lock (&fds_mutex);
129 
130 	if (!g_hash_table_lookup_extended (fds, GINT_TO_POINTER(fd), NULL, (gpointer*) &fdhandle)) {
131 		mono_coop_mutex_unlock (&fds_mutex);
132 
133 		return FALSE;
134 	}
135 
136 	removed = g_hash_table_remove (fds, GINT_TO_POINTER(fdhandle->fd));
137 	g_assert (removed);
138 
139 	mono_coop_mutex_unlock (&fds_mutex);
140 
141 	return TRUE;
142 }
143