* roottypes.cs: Rename from tree.cs.
[mono.git] / mono / io-layer / handles-private.h
1 /*
2  * handles-private.h:  Internal operations on handles
3  *
4  * Author:
5  *      Dick Porter (dick@ximian.com)
6  *
7  * (C) 2002-2006 Novell, Inc.
8  */
9
10 #ifndef _WAPI_HANDLES_PRIVATE_H_
11 #define _WAPI_HANDLES_PRIVATE_H_
12
13 #include <config.h>
14 #include <glib.h>
15 #include <errno.h>
16 #include <signal.h>
17 #include <string.h>
18 #include <sys/types.h>
19
20 #include <mono/io-layer/wapi-private.h>
21 #include <mono/io-layer/misc-private.h>
22 #include <mono/io-layer/collection.h>
23 #include <mono/io-layer/shared.h>
24
25 #define _WAPI_PRIVATE_MAX_SLOTS         1024
26 #define _WAPI_PRIVATE_HANDLES(x) (_wapi_private_handles [x / _WAPI_HANDLE_INITIAL_COUNT][x % _WAPI_HANDLE_INITIAL_COUNT])
27 #define _WAPI_PRIVATE_HAVE_SLOT(x) ((GPOINTER_TO_UINT (x) / _WAPI_PRIVATE_MAX_SLOTS) < _WAPI_PRIVATE_MAX_SLOTS && \
28                                         _wapi_private_handles [GPOINTER_TO_UINT (x) / _WAPI_HANDLE_INITIAL_COUNT] != NULL)
29 #define _WAPI_PRIVATE_VALID_SLOT(x) (((x) / _WAPI_HANDLE_INITIAL_COUNT) < _WAPI_PRIVATE_MAX_SLOTS)
30
31 #undef DEBUG
32
33 extern struct _WapiHandleUnshared *_wapi_private_handles [];
34 extern struct _WapiHandleSharedLayout *_wapi_shared_layout;
35 extern struct _WapiFileShareLayout *_wapi_fileshare_layout;
36
37 extern guint32 _wapi_fd_reserve;
38 extern mono_mutex_t _wapi_global_signal_mutex;
39 extern pthread_cond_t _wapi_global_signal_cond;
40 extern int _wapi_sem_id;
41
42 extern pid_t _wapi_getpid (void);
43 extern gpointer _wapi_handle_new (WapiHandleType type,
44                                   gpointer handle_specific);
45 extern gpointer _wapi_handle_new_fd (WapiHandleType type, int fd,
46                                      gpointer handle_specific);
47 extern gpointer _wapi_handle_new_from_offset (WapiHandleType type,
48                                               guint32 offset,
49                                               gboolean timestamp);
50 extern gboolean _wapi_lookup_handle (gpointer handle, WapiHandleType type,
51                                      gpointer *handle_specific);
52 extern gpointer _wapi_search_handle (WapiHandleType type,
53                                      gboolean (*check)(gpointer, gpointer),
54                                      gpointer user_data,
55                                      gpointer *handle_specific,
56                                      gboolean search_shared);
57 extern gint32 _wapi_search_handle_namespace (WapiHandleType type,
58                                              gchar *utf8_name);
59 extern void _wapi_handle_ref (gpointer handle);
60 extern void _wapi_handle_unref (gpointer handle);
61 extern void _wapi_handle_register_capabilities (WapiHandleType type,
62                                                 WapiHandleCapability caps);
63 extern gboolean _wapi_handle_test_capabilities (gpointer handle,
64                                                 WapiHandleCapability caps);
65 extern void _wapi_handle_ops_close (gpointer handle, gpointer data);
66 extern void _wapi_handle_ops_signal (gpointer handle);
67 extern gboolean _wapi_handle_ops_own (gpointer handle);
68 extern gboolean _wapi_handle_ops_isowned (gpointer handle);
69 extern guint32 _wapi_handle_ops_special_wait (gpointer handle,
70                                               guint32 timeout);
71 extern void _wapi_handle_ops_prewait (gpointer handle);
72
73 extern gboolean _wapi_handle_count_signalled_handles (guint32 numhandles,
74                                                       gpointer *handles,
75                                                       gboolean waitall,
76                                                       guint32 *retcount,
77                                                       guint32 *lowest);
78 extern void _wapi_handle_unlock_handles (guint32 numhandles,
79                                          gpointer *handles);
80 extern int _wapi_handle_wait_signal (void);
81 extern int _wapi_handle_timedwait_signal (struct timespec *timeout);
82 extern int _wapi_handle_wait_signal_handle (gpointer handle);
83 extern int _wapi_handle_timedwait_signal_handle (gpointer handle,
84                                                  struct timespec *timeout);
85 extern gboolean _wapi_handle_get_or_set_share (dev_t device, ino_t inode,
86                                                guint32 new_sharemode,
87                                                guint32 new_access,
88                                                guint32 *old_sharemode,
89                                                guint32 *old_access,
90                                                struct _WapiFileShare **info);
91 extern void _wapi_handle_check_share (struct _WapiFileShare *share_info,
92                                       int fd);
93 extern void _wapi_handle_dump (void);
94 extern void _wapi_handle_update_refs (void);
95 extern void _wapi_handle_foreach (WapiHandleType type,
96                                         gboolean (*on_each)(gpointer test, gpointer user),
97                                         gpointer user_data);
98
99 /* This is OK to use for atomic writes of individual struct members, as they
100  * are independent
101  */
102 #define WAPI_SHARED_HANDLE_DATA(handle) _wapi_shared_layout->handles[_WAPI_PRIVATE_HANDLES(GPOINTER_TO_UINT((handle))).u.shared.offset]
103
104 #define WAPI_SHARED_HANDLE_TYPED_DATA(handle, type) _wapi_shared_layout->handles[_WAPI_PRIVATE_HANDLES(GPOINTER_TO_UINT((handle))).u.shared.offset].u.type
105
106 static inline WapiHandleType _wapi_handle_type (gpointer handle)
107 {
108         guint32 idx = GPOINTER_TO_UINT(handle);
109         
110         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
111                 return(WAPI_HANDLE_COUNT);      /* An impossible type */
112         }
113         
114         return(_WAPI_PRIVATE_HANDLES(idx).type);
115 }
116
117 static inline void _wapi_handle_set_signal_state (gpointer handle,
118                                                   gboolean state,
119                                                   gboolean broadcast)
120 {
121         guint32 idx = GPOINTER_TO_UINT(handle);
122         struct _WapiHandleUnshared *handle_data;
123         int thr_ret;
124
125         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
126                 return;
127         }
128         
129         g_assert (!_WAPI_SHARED_HANDLE(_wapi_handle_type (handle)));
130         
131         handle_data = &_WAPI_PRIVATE_HANDLES(idx);
132         
133 #ifdef DEBUG
134         g_message ("%s: setting state of %p to %s (broadcast %s)", __func__,
135                    handle, state?"TRUE":"FALSE", broadcast?"TRUE":"FALSE");
136 #endif
137
138         if (state == TRUE) {
139                 /* Tell everyone blocking on a single handle */
140
141                 /* This function _must_ be called with
142                  * handle->signal_mutex locked
143                  */
144                 handle_data->signalled=state;
145                 
146                 if (broadcast == TRUE) {
147                         thr_ret = pthread_cond_broadcast (&handle_data->signal_cond);
148                         g_assert (thr_ret == 0);
149                 } else {
150                         thr_ret = pthread_cond_signal (&handle_data->signal_cond);
151                         g_assert (thr_ret == 0);
152                 }
153
154                 /* Tell everyone blocking on multiple handles that something
155                  * was signalled
156                  */
157                 pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup, (void *)&_wapi_global_signal_mutex);
158                 thr_ret = mono_mutex_lock (&_wapi_global_signal_mutex);
159                 g_assert (thr_ret == 0);
160                         
161                 thr_ret = pthread_cond_broadcast (&_wapi_global_signal_cond);
162                 g_assert (thr_ret == 0);
163                         
164                 thr_ret = mono_mutex_unlock (&_wapi_global_signal_mutex);
165                 g_assert (thr_ret == 0);
166                 pthread_cleanup_pop (0);
167         } else {
168                 handle_data->signalled=state;
169         }
170 }
171
172 static inline void _wapi_shared_handle_set_signal_state (gpointer handle,
173                                                          gboolean state)
174 {
175         guint32 idx = GPOINTER_TO_UINT(handle);
176         struct _WapiHandleUnshared *handle_data;
177         struct _WapiHandle_shared_ref *ref;
178         struct _WapiHandleShared *shared_data;
179         
180         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
181                 return;
182         }
183         
184         g_assert (_WAPI_SHARED_HANDLE(_wapi_handle_type (handle)));
185         
186         handle_data = &_WAPI_PRIVATE_HANDLES(idx);
187         
188         ref = &handle_data->u.shared;
189         shared_data = &_wapi_shared_layout->handles[ref->offset];
190         shared_data->signalled = state;
191
192 #ifdef DEBUG
193         g_message ("%s: signalled shared handle offset 0x%x", __func__,
194                    ref->offset);
195 #endif
196 }
197
198 static inline gboolean _wapi_handle_issignalled (gpointer handle)
199 {
200         guint32 idx = GPOINTER_TO_UINT(handle);
201         
202         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
203                 return(FALSE);
204         }
205         
206         if (_WAPI_SHARED_HANDLE(_wapi_handle_type (handle))) {
207                 return(WAPI_SHARED_HANDLE_DATA(handle).signalled);
208         } else {
209                 return(_WAPI_PRIVATE_HANDLES(idx).signalled);
210         }
211 }
212
213 static inline int _wapi_handle_lock_signal_mutex (void)
214 {
215 #ifdef DEBUG
216         g_message ("%s: lock global signal mutex", __func__);
217 #endif
218
219         return(mono_mutex_lock (&_wapi_global_signal_mutex));
220 }
221
222 /* the parameter makes it easier to call from a pthread cleanup handler */
223 static inline int _wapi_handle_unlock_signal_mutex (void *unused)
224 {
225 #ifdef DEBUG
226         g_message ("%s: unlock global signal mutex", __func__);
227 #endif
228
229         return(mono_mutex_unlock (&_wapi_global_signal_mutex));
230 }
231
232 static inline int _wapi_handle_lock_handle (gpointer handle)
233 {
234         guint32 idx = GPOINTER_TO_UINT(handle);
235         
236 #ifdef DEBUG
237         g_message ("%s: locking handle %p", __func__, handle);
238 #endif
239
240         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
241                 return(0);
242         }
243         
244         _wapi_handle_ref (handle);
245         
246         if (_WAPI_SHARED_HANDLE (_wapi_handle_type (handle))) {
247                 return(0);
248         }
249         
250         return(mono_mutex_lock (&_WAPI_PRIVATE_HANDLES(idx).signal_mutex));
251 }
252
253 static inline int _wapi_handle_trylock_handle (gpointer handle)
254 {
255         guint32 idx = GPOINTER_TO_UINT(handle);
256         int ret;
257         
258 #ifdef DEBUG
259         g_message ("%s: locking handle %p", __func__, handle);
260 #endif
261
262         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
263                 return(0);
264         }
265         
266         _wapi_handle_ref (handle);
267         
268         if (_WAPI_SHARED_HANDLE (_wapi_handle_type (handle))) {
269                 return(0);
270         }
271
272         ret = mono_mutex_trylock (&_WAPI_PRIVATE_HANDLES(idx).signal_mutex);
273         if (ret != 0) {
274                 _wapi_handle_unref (handle);
275         }
276         
277         return(ret);
278 }
279
280 static inline int _wapi_handle_unlock_handle (gpointer handle)
281 {
282         guint32 idx = GPOINTER_TO_UINT(handle);
283         int ret;
284         
285 #ifdef DEBUG
286         g_message ("%s: unlocking handle %p", __func__, handle);
287 #endif
288         
289         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
290                 return(0);
291         }
292         
293         if (_WAPI_SHARED_HANDLE (_wapi_handle_type (handle))) {
294                 _wapi_handle_unref (handle);
295                 return(0);
296         }
297         
298         ret = mono_mutex_unlock (&_WAPI_PRIVATE_HANDLES(idx).signal_mutex);
299
300         _wapi_handle_unref (handle);
301         
302         return(ret);
303 }
304
305 static inline void _wapi_handle_spin (guint32 ms)
306 {
307         struct timespec sleepytime;
308         
309         g_assert (ms < 1000);
310         
311         sleepytime.tv_sec = 0;
312         sleepytime.tv_nsec = ms * 1000000;
313         
314         nanosleep (&sleepytime, NULL);
315 }
316
317 static inline int _wapi_handle_lock_shared_handles (void)
318 {
319         return(_wapi_shm_sem_lock (_WAPI_SHARED_SEM_SHARED_HANDLES));
320 }
321
322 static inline int _wapi_handle_trylock_shared_handles (void)
323 {
324         return(_wapi_shm_sem_trylock (_WAPI_SHARED_SEM_SHARED_HANDLES));
325 }
326
327 static inline int _wapi_handle_unlock_shared_handles (void)
328 {
329         return(_wapi_shm_sem_unlock (_WAPI_SHARED_SEM_SHARED_HANDLES));
330 }
331
332 static inline int _wapi_namespace_lock (void)
333 {
334         return(_wapi_shm_sem_lock (_WAPI_SHARED_SEM_NAMESPACE));
335 }
336
337 /* This signature makes it easier to use in pthread cleanup handlers */
338 static inline int _wapi_namespace_unlock (gpointer data G_GNUC_UNUSED)
339 {
340         return(_wapi_shm_sem_unlock (_WAPI_SHARED_SEM_NAMESPACE));
341 }
342
343 static inline void _wapi_handle_share_release (struct _WapiFileShare *info)
344 {
345         int thr_ret;
346         
347         g_assert (info->handle_refs > 0);
348         
349         /* Prevent new entries racing with us */
350         thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
351         g_assert(thr_ret == 0);
352
353         if (InterlockedDecrement ((gint32 *)&info->handle_refs) == 0) {
354                 memset (info, '\0', sizeof(struct _WapiFileShare));
355         }
356
357         thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
358 }
359
360 #endif /* _WAPI_HANDLES_PRIVATE_H_ */