[runtime] Updates comments.
[mono.git] / mono / io-layer / handles.c
1 /*
2  * handles.c:  Generic and internal operations on handles
3  *
4  * Author:
5  *      Dick Porter (dick@ximian.com)
6  *
7  * (C) 2002-2011 Novell, Inc.
8  * Copyright 2011 Xamarin Inc
9  */
10
11 #include <config.h>
12 #include <glib.h>
13 #include <pthread.h>
14 #include <errno.h>
15 #include <unistd.h>
16 #ifdef HAVE_SIGNAL_H
17 #include <signal.h>
18 #endif
19 #include <string.h>
20 #include <sys/types.h>
21 #ifdef HAVE_SYS_SOCKET_H
22 #  include <sys/socket.h>
23 #endif
24 #ifdef HAVE_SYS_UN_H
25 #  include <sys/un.h>
26 #endif
27 #ifdef HAVE_SYS_MMAN_H
28 #  include <sys/mman.h>
29 #endif
30 #ifdef HAVE_DIRENT_H
31 #  include <dirent.h>
32 #endif
33 #include <sys/stat.h>
34 #ifdef HAVE_SYS_RESOURCE_H
35 #  include <sys/resource.h>
36 #endif
37
38 #include <mono/io-layer/wapi.h>
39 #include <mono/io-layer/wapi-private.h>
40 #include <mono/io-layer/handles-private.h>
41 #include <mono/io-layer/misc-private.h>
42 #include <mono/io-layer/shared.h>
43 #include <mono/io-layer/collection.h>
44 #include <mono/io-layer/process-private.h>
45
46 #include <mono/utils/mono-mutex.h>
47 #include <mono/utils/mono-proclib.h>
48 #undef DEBUG_REFS
49
50 #if 0
51 #define DEBUG(...) g_message(__VA_ARGS__)
52 #else
53 #define DEBUG(...)
54 #endif
55
56 static void (*_wapi_handle_ops_get_close_func (WapiHandleType type))(gpointer, gpointer);
57
58 static WapiHandleCapability handle_caps[WAPI_HANDLE_COUNT]={0};
59 static struct _WapiHandleOps *handle_ops[WAPI_HANDLE_COUNT]={
60         NULL,
61         &_wapi_file_ops,
62         &_wapi_console_ops,
63         &_wapi_thread_ops,
64         &_wapi_sem_ops,
65         &_wapi_mutex_ops,
66         &_wapi_event_ops,
67 #ifndef DISABLE_SOCKETS
68         &_wapi_socket_ops,
69 #endif
70         &_wapi_find_ops,
71         &_wapi_process_ops,
72         &_wapi_pipe_ops,
73         &_wapi_namedmutex_ops,
74         &_wapi_namedsem_ops,
75         &_wapi_namedevent_ops,
76 };
77
78 static void _wapi_shared_details (gpointer handle_info);
79
80 static void (*handle_details[WAPI_HANDLE_COUNT])(gpointer) = {
81         NULL,
82         _wapi_file_details,
83         _wapi_console_details,
84         _wapi_shared_details,   /* thread */
85         _wapi_sem_details,
86         _wapi_mutex_details,
87         _wapi_event_details,
88         NULL,                   /* Nothing useful to see in a socket handle */
89         NULL,                   /* Nothing useful to see in a find handle */
90         _wapi_shared_details,   /* process */
91         _wapi_pipe_details,
92         _wapi_shared_details,   /* namedmutex */
93         _wapi_shared_details,   /* namedsem */
94         _wapi_shared_details,   /* namedevent */
95 };
96
97 const char *_wapi_handle_typename[] = {
98         "Unused",
99         "File",
100         "Console",
101         "Thread",
102         "Sem",
103         "Mutex",
104         "Event",
105         "Socket",
106         "Find",
107         "Process",
108         "Pipe",
109         "N.Mutex",
110         "N.Sem",
111         "N.Event",
112         "Error!!"
113 };
114
115 /*
116  * We can hold _WAPI_PRIVATE_MAX_SLOTS * _WAPI_HANDLE_INITIAL_COUNT handles.
117  * If 4M handles are not enough... Oh, well... we will crash.
118  */
119 #define SLOT_INDEX(x)   (x / _WAPI_HANDLE_INITIAL_COUNT)
120 #define SLOT_OFFSET(x)  (x % _WAPI_HANDLE_INITIAL_COUNT)
121
122 struct _WapiHandleUnshared *_wapi_private_handles [_WAPI_PRIVATE_MAX_SLOTS];
123 static guint32 _wapi_private_handle_count = 0;
124 static guint32 _wapi_private_handle_slot_count = 0;
125
126 struct _WapiHandleSharedLayout *_wapi_shared_layout = NULL;
127
128 /*
129  * If SHM is enabled, this will point to shared memory, otherwise it will be NULL.
130  */
131 struct _WapiFileShareLayout *_wapi_fileshare_layout = NULL;
132
133 /*
134  * If SHM is disabled, this will point to a hash of _WapiFileShare structures, otherwise
135  * it will be NULL. We use this instead of _wapi_fileshare_layout to avoid allocating a
136  * 4MB array.
137  */
138 static GHashTable *file_share_hash;
139 static mono_mutex_t file_share_hash_mutex;
140
141 #define file_share_hash_lock() mono_mutex_lock (&file_share_hash_mutex)
142 #define file_share_hash_unlock() mono_mutex_unlock (&file_share_hash_mutex)
143
144 guint32 _wapi_fd_reserve;
145
146 /* 
147  * This is an internal handle which is used for handling waiting for multiple handles.
148  * Threads which wait for multiple handles wait on this one handle, and when a handle
149  * is signalled, this handle is signalled too.
150  */
151 static gpointer _wapi_global_signal_handle;
152
153 /* Point to the mutex/cond inside _wapi_global_signal_handle */
154 mono_mutex_t *_wapi_global_signal_mutex;
155 pthread_cond_t *_wapi_global_signal_cond;
156
157 int _wapi_sem_id;
158 gboolean _wapi_has_shut_down = FALSE;
159
160 /* Use this instead of getpid(), to cope with linuxthreads.  It's a
161  * function rather than a variable lookup because we need to get at
162  * this before share_init() might have been called.
163  */
164 static pid_t _wapi_pid;
165 static mono_once_t pid_init_once = MONO_ONCE_INIT;
166
167 static void _wapi_handle_unref_full (gpointer handle, gboolean ignore_private_busy_handles);
168
169 static void pid_init (void)
170 {
171         _wapi_pid = getpid ();
172 }
173
174 pid_t _wapi_getpid (void)
175 {
176         mono_once (&pid_init_once, pid_init);
177         
178         return(_wapi_pid);
179 }
180
181
182 static mono_mutex_t scan_mutex;
183
184 static void handle_cleanup (void)
185 {
186         int i, j, k;
187         
188         /* Every shared handle we were using ought really to be closed
189          * by now, but to make sure just blow them all away.  The
190          * exiting finalizer thread in particular races us to the
191          * program exit and doesn't always win, so it can be left
192          * cluttering up the shared file.  Anything else left over is
193          * really a bug.
194          */
195         for(i = SLOT_INDEX (0); _wapi_private_handles[i] != NULL; i++) {
196                 for(j = SLOT_OFFSET (0); j < _WAPI_HANDLE_INITIAL_COUNT; j++) {
197                         struct _WapiHandleUnshared *handle_data = &_wapi_private_handles[i][j];
198                         gpointer handle = GINT_TO_POINTER (i*_WAPI_HANDLE_INITIAL_COUNT+j);
199
200                         for(k = handle_data->ref; k > 0; k--) {
201                                 DEBUG ("%s: unreffing %s handle %p", __func__, _wapi_handle_typename[type], handle);
202                                         
203                                 _wapi_handle_unref_full (handle, TRUE);
204                         }
205                 }
206         }
207         
208         _wapi_shm_semaphores_remove ();
209
210         _wapi_shm_detach (WAPI_SHM_DATA);
211         _wapi_shm_detach (WAPI_SHM_FILESHARE);
212
213         if (file_share_hash) {
214                 g_hash_table_destroy (file_share_hash);
215                 mono_mutex_destroy (&file_share_hash_mutex);
216         }
217
218         for (i = 0; i < _WAPI_PRIVATE_MAX_SLOTS; ++i)
219                 g_free (_wapi_private_handles [i]);
220 }
221
222 int
223 wapi_getdtablesize (void)
224 {
225         return eg_getdtablesize ();
226 }
227
228 /*
229  * wapi_init:
230  *
231  *   Initialize the io-layer.
232  */
233 void
234 wapi_init (void)
235 {
236         g_assert ((sizeof (handle_ops) / sizeof (handle_ops[0]))
237                   == WAPI_HANDLE_COUNT);
238
239         _wapi_fd_reserve = wapi_getdtablesize ();
240
241         /* This is needed by the code in _wapi_handle_new_internal */
242         _wapi_fd_reserve = (_wapi_fd_reserve + (_WAPI_HANDLE_INITIAL_COUNT - 1)) & ~(_WAPI_HANDLE_INITIAL_COUNT - 1);
243
244         do {
245                 /* 
246                  * The entries in _wapi_private_handles reserved for fds are allocated lazily to 
247                  * save memory.
248                  */
249                 /*
250                 _wapi_private_handles [idx++] = g_new0 (struct _WapiHandleUnshared,
251                                                         _WAPI_HANDLE_INITIAL_COUNT);
252                 */
253
254                 _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
255                 _wapi_private_handle_slot_count ++;
256         } while(_wapi_fd_reserve > _wapi_private_handle_count);
257
258         _wapi_shm_semaphores_init ();
259         
260         _wapi_shared_layout = _wapi_shm_attach (WAPI_SHM_DATA);
261         g_assert (_wapi_shared_layout != NULL);
262         
263         if (_wapi_shm_enabled ()) {
264                 /* This allocates a 4mb array, so do it only if SHM is enabled */
265                 _wapi_fileshare_layout = _wapi_shm_attach (WAPI_SHM_FILESHARE);
266                 g_assert (_wapi_fileshare_layout != NULL);
267         }
268         
269 #if !defined (DISABLE_SHARED_HANDLES)
270         if (_wapi_shm_enabled ())
271                 _wapi_collection_init ();
272 #endif
273         _wapi_io_init ();
274         mono_mutex_init (&scan_mutex);
275
276         _wapi_global_signal_handle = _wapi_handle_new (WAPI_HANDLE_EVENT, NULL);
277
278         _wapi_global_signal_cond = &_WAPI_PRIVATE_HANDLES (GPOINTER_TO_UINT (_wapi_global_signal_handle)).signal_cond;
279         _wapi_global_signal_mutex = &_WAPI_PRIVATE_HANDLES (GPOINTER_TO_UINT (_wapi_global_signal_handle)).signal_mutex;
280
281         wapi_processes_init ();
282
283         /* Using atexit here instead of an explicit function call in
284          * a cleanup routine lets us cope when a third-party library
285          * calls exit (eg if an X client loses the connection to its
286          * server.)
287          */
288         mono_atexit (handle_cleanup);
289 }
290
291 void
292 wapi_cleanup (void)
293 {
294         g_assert (_wapi_has_shut_down == FALSE);
295         
296         _wapi_has_shut_down = TRUE;
297
298         _wapi_error_cleanup ();
299         _wapi_thread_cleanup ();
300         wapi_processes_cleanup ();
301 }
302
303 static void _wapi_handle_init_shared (struct _WapiHandleShared *handle,
304                                       WapiHandleType type,
305                                       gpointer handle_specific)
306 {
307         g_assert (_wapi_has_shut_down == FALSE);
308         
309         handle->type = type;
310         handle->timestamp = (guint32)(time (NULL) & 0xFFFFFFFF);
311         handle->signalled = FALSE;
312         handle->handle_refs = 1;
313         
314         if (handle_specific != NULL) {
315                 memcpy (&handle->u, handle_specific, sizeof (handle->u));
316         }
317 }
318
319 static size_t _wapi_handle_struct_size (WapiHandleType type)
320 {
321         size_t type_size;
322
323         switch (type) {
324                 case WAPI_HANDLE_FILE: case WAPI_HANDLE_CONSOLE: case WAPI_HANDLE_PIPE:
325                         type_size = sizeof (struct _WapiHandle_file);
326                         break;
327                 case WAPI_HANDLE_THREAD:
328                         type_size = sizeof (struct _WapiHandle_thread);
329                         break;
330                 case WAPI_HANDLE_SEM:
331                         type_size = sizeof (struct _WapiHandle_sem);
332                         break;
333                 case WAPI_HANDLE_MUTEX:
334                         type_size = sizeof (struct _WapiHandle_mutex);
335                         break;
336                 case WAPI_HANDLE_EVENT:
337                         type_size = sizeof (struct _WapiHandle_event);
338                         break;
339                 case WAPI_HANDLE_SOCKET:
340                         type_size = sizeof (struct _WapiHandle_socket);
341                         break;
342                 case WAPI_HANDLE_FIND:
343                         type_size = sizeof (struct _WapiHandle_find);
344                         break;
345                 case WAPI_HANDLE_PROCESS:
346                         type_size = sizeof (struct _WapiHandle_process);
347                         break;
348                 case WAPI_HANDLE_NAMEDMUTEX:
349                         type_size = sizeof (struct _WapiHandle_namedmutex);
350                         break;
351                 case WAPI_HANDLE_NAMEDSEM:
352                         type_size = sizeof (struct _WapiHandle_namedsem);
353                         break;
354                 case WAPI_HANDLE_NAMEDEVENT:
355                         type_size = sizeof (struct _WapiHandle_namedevent);
356                         break;
357
358                 default:
359                         g_error ("Unknown WapiHandleType: %d\n", type);
360         }
361
362         return type_size;
363 }
364
365 static void _wapi_handle_init (struct _WapiHandleUnshared *handle,
366                                WapiHandleType type, gpointer handle_specific)
367 {
368         int thr_ret;
369         int type_size;
370         
371         g_assert (_wapi_has_shut_down == FALSE);
372         
373         handle->type = type;
374         handle->signalled = FALSE;
375         handle->ref = 1;
376         
377         if (!_WAPI_SHARED_HANDLE(type)) {
378                 thr_ret = pthread_cond_init (&handle->signal_cond, NULL);
379                 g_assert (thr_ret == 0);
380                                 
381                 thr_ret = mono_mutex_init (&handle->signal_mutex);
382                 g_assert (thr_ret == 0);
383
384                 if (handle_specific != NULL) {
385                         type_size = _wapi_handle_struct_size (type);
386                         memcpy (&handle->u, handle_specific,
387                                 type_size);
388                 }
389         }
390 }
391
392 static guint32 _wapi_handle_new_shared (WapiHandleType type,
393                                         gpointer handle_specific)
394 {
395         guint32 offset;
396         static guint32 last = 1;
397         int thr_ret;
398         
399         g_assert (_wapi_has_shut_down == FALSE);
400         
401         /* Leave the first slot empty as a guard */
402 again:
403         /* FIXME: expandable array */
404         for(offset = last; offset <_WAPI_HANDLE_INITIAL_COUNT; offset++) {
405                 struct _WapiHandleShared *handle = &_wapi_shared_layout->handles[offset];
406                 
407                 if(handle->type == WAPI_HANDLE_UNUSED) {
408                         thr_ret = _wapi_handle_lock_shared_handles ();
409                         g_assert (thr_ret == 0);
410                         
411                         if (InterlockedCompareExchange ((gint32 *)&handle->type, type, WAPI_HANDLE_UNUSED) == WAPI_HANDLE_UNUSED) {
412                                 last = offset + 1;
413                         
414                                 _wapi_handle_init_shared (handle, type,
415                                                           handle_specific);
416
417                                 _wapi_handle_unlock_shared_handles ();
418                                 
419                                 return(offset);
420                         } else {
421                                 /* Someone else beat us to it, just
422                                  * continue looking
423                                  */
424                         }
425
426                         _wapi_handle_unlock_shared_handles ();
427                 }
428         }
429
430         if(last > 1) {
431                 /* Try again from the beginning */
432                 last = 1;
433                 goto again;
434         }
435
436         /* Will need to expand the array.  The caller will sort it out */
437
438         return(0);
439 }
440
441 /*
442  * _wapi_handle_new_internal:
443  * @type: Init handle to this type
444  *
445  * Search for a free handle and initialize it. Return the handle on
446  * success and 0 on failure.  This is only called from
447  * _wapi_handle_new, and scan_mutex must be held.
448  */
449 static guint32 _wapi_handle_new_internal (WapiHandleType type,
450                                           gpointer handle_specific)
451 {
452         guint32 i, k, count;
453         static guint32 last = 0;
454         gboolean retry = FALSE;
455         
456         g_assert (_wapi_has_shut_down == FALSE);
457         
458         /* A linear scan should be fast enough.  Start from the last
459          * allocation, assuming that handles are allocated more often
460          * than they're freed. Leave the space reserved for file
461          * descriptors
462          */
463         
464         if (last < _wapi_fd_reserve) {
465                 last = _wapi_fd_reserve;
466         } else {
467                 retry = TRUE;
468         }
469
470 again:
471         count = last;
472         for(i = SLOT_INDEX (count); i < _wapi_private_handle_slot_count; i++) {
473                 if (_wapi_private_handles [i]) {
474                         for (k = SLOT_OFFSET (count); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
475                                 struct _WapiHandleUnshared *handle = &_wapi_private_handles [i][k];
476
477                                 if(handle->type == WAPI_HANDLE_UNUSED) {
478                                         last = count + 1;
479                         
480                                         _wapi_handle_init (handle, type, handle_specific);
481                                         return (count);
482                                 }
483                                 count++;
484                         }
485                 }
486         }
487
488         if(retry && last > _wapi_fd_reserve) {
489                 /* Try again from the beginning */
490                 last = _wapi_fd_reserve;
491                 goto again;
492         }
493
494         /* Will need to expand the array.  The caller will sort it out */
495
496         return(0);
497 }
498
499 gpointer 
500 _wapi_handle_new (WapiHandleType type, gpointer handle_specific)
501 {
502         guint32 handle_idx = 0;
503         gpointer handle;
504         int thr_ret;
505
506         g_assert (_wapi_has_shut_down == FALSE);
507                 
508         DEBUG ("%s: Creating new handle of type %s", __func__,
509                    _wapi_handle_typename[type]);
510
511         g_assert(!_WAPI_FD_HANDLE(type));
512         
513         thr_ret = mono_mutex_lock (&scan_mutex);
514         g_assert (thr_ret == 0);
515                 
516         while ((handle_idx = _wapi_handle_new_internal (type, handle_specific)) == 0) {
517                 /* Try and expand the array, and have another go */
518                 int idx = SLOT_INDEX (_wapi_private_handle_count);
519                 if (idx >= _WAPI_PRIVATE_MAX_SLOTS) {
520                         break;
521                 }
522
523                 _wapi_private_handles [idx] = g_new0 (struct _WapiHandleUnshared,
524                                                 _WAPI_HANDLE_INITIAL_COUNT);
525
526                 _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
527                 _wapi_private_handle_slot_count ++;
528         }
529         
530         thr_ret = mono_mutex_unlock (&scan_mutex);
531         g_assert (thr_ret == 0);
532
533         if (handle_idx == 0) {
534                 /* We ran out of slots */
535                 handle = _WAPI_HANDLE_INVALID;
536                 goto done;
537         }
538                 
539         /* Make sure we left the space for fd mappings */
540         g_assert (handle_idx >= _wapi_fd_reserve);
541         
542         handle = GUINT_TO_POINTER (handle_idx);
543
544         DEBUG ("%s: Allocated new handle %p", __func__, handle);
545         
546         if (_WAPI_SHARED_HANDLE(type)) {
547                 /* Add the shared section too */
548                 guint32 ref;
549                 
550                 ref = _wapi_handle_new_shared (type, handle_specific);
551                 if (ref == 0) {
552                         _wapi_handle_collect ();
553                         ref = _wapi_handle_new_shared (type, handle_specific);
554                         if (ref == 0) {
555                                 /* FIXME: grow the arrays */
556                                 handle = _WAPI_HANDLE_INVALID;
557                                 goto done;
558                         }
559                 }
560                 
561                 _WAPI_PRIVATE_HANDLES(handle_idx).u.shared.offset = ref;
562                 DEBUG ("%s: New shared handle at offset 0x%x", __func__,
563                            ref);
564         }
565                 
566 done:
567         return(handle);
568 }
569
570 gpointer _wapi_handle_new_from_offset (WapiHandleType type, guint32 offset,
571                                        gboolean timestamp)
572 {
573         guint32 handle_idx = 0;
574         gpointer handle = INVALID_HANDLE_VALUE;
575         int thr_ret, i, k;
576         struct _WapiHandleShared *shared;
577         
578         g_assert (_wapi_has_shut_down == FALSE);
579         
580         DEBUG ("%s: Creating new handle of type %s to offset %d", __func__,
581                    _wapi_handle_typename[type], offset);
582
583         g_assert(!_WAPI_FD_HANDLE(type));
584         g_assert(_WAPI_SHARED_HANDLE(type));
585         g_assert(offset != 0);
586
587         shared = &_wapi_shared_layout->handles[offset];
588         if (timestamp) {
589                 guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
590                 /* Bump up the timestamp for this offset */
591                 InterlockedExchange ((gint32 *)&shared->timestamp, now);
592         }
593                 
594         thr_ret = mono_mutex_lock (&scan_mutex);
595         g_assert (thr_ret == 0);
596
597         for (i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) {
598                 if (_wapi_private_handles [i]) {
599                         for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
600                                 struct _WapiHandleUnshared *handle_data = &_wapi_private_handles [i][k];
601                 
602                                 if (handle_data->type == type &&
603                                         handle_data->u.shared.offset == offset) {
604                                         handle = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
605                                         goto first_pass_done;
606                                 }
607                         }
608                 }
609         }
610
611 first_pass_done:
612         thr_ret = mono_mutex_unlock (&scan_mutex);
613         g_assert (thr_ret == 0);
614
615         if (handle != INVALID_HANDLE_VALUE) {
616                 _wapi_handle_ref (handle);
617
618                 DEBUG ("%s: Returning old handle %p referencing 0x%x",
619                            __func__, handle, offset);
620                 return (handle);
621         }
622
623         /* Prevent entries expiring under us as we search */
624         thr_ret = _wapi_handle_lock_shared_handles ();
625         g_assert (thr_ret == 0);
626         
627         if (shared->type == WAPI_HANDLE_UNUSED) {
628                 /* Someone deleted this handle while we were working */
629                 DEBUG ("%s: Handle at 0x%x unused", __func__, offset);
630                 goto done;
631         }
632
633         if (shared->type != type) {
634                 DEBUG ("%s: Wrong type at %d 0x%x! Found %s wanted %s",
635                            __func__, offset, offset,
636                            _wapi_handle_typename[shared->type],
637                            _wapi_handle_typename[type]);
638                 goto done;
639         }
640         
641         thr_ret = mono_mutex_lock (&scan_mutex);
642         g_assert (thr_ret == 0);
643         
644         while ((handle_idx = _wapi_handle_new_internal (type, NULL)) == 0) {
645                 /* Try and expand the array, and have another go */
646                 int idx = SLOT_INDEX (_wapi_private_handle_count);
647                 _wapi_private_handles [idx] = g_new0 (struct _WapiHandleUnshared,
648                                                 _WAPI_HANDLE_INITIAL_COUNT);
649
650                 _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
651                 _wapi_private_handle_slot_count ++;
652         }
653                 
654         thr_ret = mono_mutex_unlock (&scan_mutex);
655         g_assert (thr_ret == 0);
656                 
657         /* Make sure we left the space for fd mappings */
658         g_assert (handle_idx >= _wapi_fd_reserve);
659         
660         handle = GUINT_TO_POINTER (handle_idx);
661                 
662         _WAPI_PRIVATE_HANDLES(handle_idx).u.shared.offset = offset;
663         InterlockedIncrement ((gint32 *)&shared->handle_refs);
664         
665         DEBUG ("%s: Allocated new handle %p referencing 0x%x (shared refs %d)", __func__, handle, offset, shared->handle_refs);
666         
667 done:
668         _wapi_handle_unlock_shared_handles ();
669
670         return(handle);
671 }
672
673 static void
674 init_handles_slot (int idx)
675 {
676         int thr_ret;
677
678         thr_ret = mono_mutex_lock (&scan_mutex);
679         g_assert (thr_ret == 0);
680
681         if (_wapi_private_handles [idx] == NULL) {
682                 _wapi_private_handles [idx] = g_new0 (struct _WapiHandleUnshared,
683                                                                                           _WAPI_HANDLE_INITIAL_COUNT);
684                 g_assert (_wapi_private_handles [idx]);
685         }
686
687         thr_ret = mono_mutex_unlock (&scan_mutex);
688         g_assert (thr_ret == 0);
689 }
690
691 gpointer _wapi_handle_new_fd (WapiHandleType type, int fd,
692                               gpointer handle_specific)
693 {
694         struct _WapiHandleUnshared *handle;
695         int thr_ret;
696         
697         g_assert (_wapi_has_shut_down == FALSE);
698         
699         DEBUG ("%s: Creating new handle of type %s", __func__,
700                    _wapi_handle_typename[type]);
701         
702         g_assert(_WAPI_FD_HANDLE(type));
703         g_assert(!_WAPI_SHARED_HANDLE(type));
704         
705         if (fd >= _wapi_fd_reserve) {
706                 DEBUG ("%s: fd %d is too big", __func__, fd);
707
708                 return(GUINT_TO_POINTER (_WAPI_HANDLE_INVALID));
709         }
710
711         /* Initialize the array entries on demand */
712         if (_wapi_private_handles [SLOT_INDEX (fd)] == NULL)
713                 init_handles_slot (SLOT_INDEX (fd));
714
715         handle = &_WAPI_PRIVATE_HANDLES(fd);
716         
717         if (handle->type != WAPI_HANDLE_UNUSED) {
718                 DEBUG ("%s: fd %d is already in use!", __func__, fd);
719                 /* FIXME: clean up this handle?  We can't do anything
720                  * with the fd, cos thats the new one
721                  */
722         }
723
724         DEBUG ("%s: Assigning new fd handle %d", __func__, fd);
725
726         /* Prevent file share entries racing with us, when the file
727          * handle is only half initialised
728          */
729         thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
730         g_assert(thr_ret == 0);
731
732         _wapi_handle_init (handle, type, handle_specific);
733
734         thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
735
736         return(GUINT_TO_POINTER(fd));
737 }
738
739 gboolean _wapi_lookup_handle (gpointer handle, WapiHandleType type,
740                               gpointer *handle_specific)
741 {
742         struct _WapiHandleUnshared *handle_data;
743         guint32 handle_idx = GPOINTER_TO_UINT(handle);
744
745         if (!_WAPI_PRIVATE_VALID_SLOT (handle_idx)) {
746                 return(FALSE);
747         }
748
749         /* Initialize the array entries on demand */
750         if (_wapi_private_handles [SLOT_INDEX (handle_idx)] == NULL)
751                 init_handles_slot (SLOT_INDEX (handle_idx));
752         
753         handle_data = &_WAPI_PRIVATE_HANDLES(handle_idx);
754         
755         if (handle_data->type != type) {
756                 return(FALSE);
757         }
758
759         if (handle_specific == NULL) {
760                 return(FALSE);
761         }
762         
763         if (_WAPI_SHARED_HANDLE(type)) {
764                 struct _WapiHandle_shared_ref *ref;
765                 struct _WapiHandleShared *shared_handle_data;
766                         
767                 ref = &handle_data->u.shared;
768                 shared_handle_data = &_wapi_shared_layout->handles[ref->offset];
769                 
770                 if (shared_handle_data->type != type) {
771                         /* The handle must have been deleted on us
772                          */
773                         return (FALSE);
774                 }
775                 
776                 *handle_specific = &shared_handle_data->u;
777         } else {
778                 *handle_specific = &handle_data->u;
779         }
780         
781         return(TRUE);
782 }
783
784 void
785 _wapi_handle_foreach (WapiHandleType type,
786                         gboolean (*on_each)(gpointer test, gpointer user),
787                         gpointer user_data)
788 {
789         struct _WapiHandleUnshared *handle_data = NULL;
790         gpointer ret = NULL;
791         guint32 i, k;
792         int thr_ret;
793
794         thr_ret = mono_mutex_lock (&scan_mutex);
795         g_assert (thr_ret == 0);
796
797         for (i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) {
798                 if (_wapi_private_handles [i]) {
799                         for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
800                                 handle_data = &_wapi_private_handles [i][k];
801                         
802                                 if (handle_data->type == type) {
803                                         ret = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
804                                         if (on_each (ret, user_data) == TRUE)
805                                                 break;
806                                 }
807                         }
808                 }
809         }
810
811         thr_ret = mono_mutex_unlock (&scan_mutex);
812         g_assert (thr_ret == 0);
813 }
814
815 /* This might list some shared handles twice if they are already
816  * opened by this process, and the check function returns FALSE the
817  * first time.  Shared handles that are created during the search are
818  * unreffed if the check function returns FALSE, so callers must not
819  * rely on the handle persisting (unless the check function returns
820  * TRUE)
821  * The caller owns the returned handle.
822  */
823 gpointer _wapi_search_handle (WapiHandleType type,
824                               gboolean (*check)(gpointer test, gpointer user),
825                               gpointer user_data,
826                               gpointer *handle_specific,
827                               gboolean search_shared)
828 {
829         struct _WapiHandleUnshared *handle_data = NULL;
830         struct _WapiHandleShared *shared = NULL;
831         gpointer ret = NULL;
832         guint32 i, k;
833         gboolean found = FALSE;
834         int thr_ret;
835
836         thr_ret = mono_mutex_lock (&scan_mutex);
837         g_assert (thr_ret == 0);
838         
839         for (i = SLOT_INDEX (0); !found && i < _wapi_private_handle_slot_count; i++) {
840                 if (_wapi_private_handles [i]) {
841                         for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
842                                 handle_data = &_wapi_private_handles [i][k];
843                 
844                                 if (handle_data->type == type) {
845                                         ret = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
846                                         if (check (ret, user_data) == TRUE) {
847                                                 _wapi_handle_ref (ret);
848                                                 found = TRUE;
849
850                                                 if (_WAPI_SHARED_HANDLE (type)) {
851                                                         shared = &_wapi_shared_layout->handles[i];
852                                                 }
853                                         
854                                                 break;
855                                         }
856                                 }
857                         }
858                 }
859         }
860
861         thr_ret = mono_mutex_unlock (&scan_mutex);
862         g_assert (thr_ret == 0);
863
864         if (!found && search_shared && _WAPI_SHARED_HANDLE (type)) {
865                 /* Not found yet, so search the shared memory too */
866                 DEBUG ("%s: Looking at other shared handles...", __func__);
867
868                 for (i = 0; i < _WAPI_HANDLE_INITIAL_COUNT; i++) {
869                         shared = &_wapi_shared_layout->handles[i];
870                         
871                         if (shared->type == type) {
872                                 /* Tell new_from_offset to not
873                                  * timestamp this handle, because
874                                  * otherwise it will ping every handle
875                                  * in the list and they will never
876                                  * expire
877                                  */
878                                 ret = _wapi_handle_new_from_offset (type, i,
879                                                                     FALSE);
880                                 if (ret == INVALID_HANDLE_VALUE) {
881                                         /* This handle was deleted
882                                          * while we were looking at it
883                                          */
884                                         continue;
885                                 }
886                                 
887                                 DEBUG ("%s: Opened tmp handle %p (type %s) from offset %d", __func__, ret, _wapi_handle_typename[type], i);
888
889                                 /* It's possible that the shared part
890                                  * of this handle has now been blown
891                                  * away (after new_from_offset
892                                  * successfully opened it,) if its
893                                  * timestamp is too old.  The check
894                                  * function needs to be aware of this,
895                                  * and cope if the handle has
896                                  * vanished.
897                                  */
898                                 if (check (ret, user_data) == TRUE) {
899                                         /* Timestamp this handle, but make
900                                          * sure it still exists first
901                                          */
902                                         thr_ret = _wapi_handle_lock_shared_handles ();
903                                         g_assert (thr_ret == 0);
904                                         
905                                         if (shared->type == type) {
906                                                 guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
907                                                 InterlockedExchange ((gint32 *)&shared->timestamp, now);
908
909                                                 found = TRUE;
910                                                 handle_data = &_WAPI_PRIVATE_HANDLES(GPOINTER_TO_UINT(ret));
911                                         
912                                                 _wapi_handle_unlock_shared_handles ();
913                                                 break;
914                                         } else {
915                                                 /* It's been deleted,
916                                                  * so just keep
917                                                  * looking
918                                                  */
919                                                 _wapi_handle_unlock_shared_handles ();
920                                         }
921                                 }
922                                 
923                                 /* This isn't the handle we're looking
924                                  * for, so drop the reference we took
925                                  * in _wapi_handle_new_from_offset ()
926                                  */
927                                 _wapi_handle_unref (ret);
928                         }
929                 }
930         }
931         
932         if (!found) {
933                 ret = NULL;
934                 goto done;
935         }
936         
937         if(handle_specific != NULL) {
938                 if (_WAPI_SHARED_HANDLE(type)) {
939                         g_assert(shared->type == type);
940                         
941                         *handle_specific = &shared->u;
942                 } else {
943                         *handle_specific = &handle_data->u;
944                 }
945         }
946
947 done:
948         return(ret);
949 }
950
951 /* Returns the offset of the metadata array, or -1 on error, or 0 for
952  * not found (0 is not a valid offset)
953  */
954 gint32 _wapi_search_handle_namespace (WapiHandleType type,
955                                       gchar *utf8_name)
956 {
957         struct _WapiHandleShared *shared_handle_data;
958         guint32 i;
959         gint32 ret = 0;
960         int thr_ret;
961         
962         g_assert(_WAPI_SHARED_HANDLE(type));
963         
964         DEBUG ("%s: Lookup for handle named [%s] type %s", __func__,
965                    utf8_name, _wapi_handle_typename[type]);
966
967         /* Do a handle collection before starting to look, so that any
968          * stale cruft gets removed
969          */
970         _wapi_handle_collect ();
971         
972         thr_ret = _wapi_handle_lock_shared_handles ();
973         g_assert (thr_ret == 0);
974         
975         for(i = 1; i < _WAPI_HANDLE_INITIAL_COUNT; i++) {
976                 WapiSharedNamespace *sharedns;
977                 
978                 shared_handle_data = &_wapi_shared_layout->handles[i];
979
980                 /* Check mutex, event, semaphore, timer, job and
981                  * file-mapping object names.  So far only mutex,
982                  * semaphore and event are implemented.
983                  */
984                 if (!_WAPI_SHARED_NAMESPACE (shared_handle_data->type)) {
985                         continue;
986                 }
987
988                 DEBUG ("%s: found a shared namespace handle at 0x%x (type %s)", __func__, i, _wapi_handle_typename[shared_handle_data->type]);
989
990                 sharedns=(WapiSharedNamespace *)&shared_handle_data->u;
991                         
992                 DEBUG ("%s: name is [%s]", __func__, sharedns->name);
993
994                 if (strcmp (sharedns->name, utf8_name) == 0) {
995                         if (shared_handle_data->type != type) {
996                                 /* Its the wrong type, so fail now */
997                                 DEBUG ("%s: handle 0x%x matches name but is wrong type: %s", __func__, i, _wapi_handle_typename[shared_handle_data->type]);
998                                 ret = -1;
999                                 goto done;
1000                         } else {
1001                                 DEBUG ("%s: handle 0x%x matches name and type", __func__, i);
1002                                 ret = i;
1003                                 goto done;
1004                         }
1005                 }
1006         }
1007
1008 done:
1009         _wapi_handle_unlock_shared_handles ();
1010         
1011         return(ret);
1012 }
1013
1014 void _wapi_handle_ref (gpointer handle)
1015 {
1016         guint32 idx = GPOINTER_TO_UINT(handle);
1017         struct _WapiHandleUnshared *handle_data;
1018
1019         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1020                 return;
1021         }
1022         
1023         if (_wapi_handle_type (handle) == WAPI_HANDLE_UNUSED) {
1024                 g_warning ("%s: Attempting to ref unused handle %p", __func__,
1025                            handle);
1026                 return;
1027         }
1028
1029         handle_data = &_WAPI_PRIVATE_HANDLES(idx);
1030         
1031         InterlockedIncrement ((gint32 *)&handle_data->ref);
1032
1033         /* It's possible for processes to exit before getting around
1034          * to updating timestamps in the collection thread, so if a
1035          * shared handle is reffed do the timestamp here as well just
1036          * to make sure.
1037          */
1038         if (_WAPI_SHARED_HANDLE(handle_data->type)) {
1039                 struct _WapiHandleShared *shared_data = &_wapi_shared_layout->handles[handle_data->u.shared.offset];
1040                 guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
1041                 InterlockedExchange ((gint32 *)&shared_data->timestamp, now);
1042         }
1043         
1044 #ifdef DEBUG_REFS
1045         g_message ("%s: %s handle %p ref now %d", __func__, 
1046                    _wapi_handle_typename[_WAPI_PRIVATE_HANDLES (idx).type],
1047                    handle,
1048                    _WAPI_PRIVATE_HANDLES(idx).ref);
1049 #endif
1050 }
1051
1052 /* The handle must not be locked on entry to this function */
1053 static void _wapi_handle_unref_full (gpointer handle, gboolean ignore_private_busy_handles)
1054 {
1055         guint32 idx = GPOINTER_TO_UINT(handle);
1056         gboolean destroy = FALSE, early_exit = FALSE;
1057         int thr_ret;
1058
1059         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1060                 return;
1061         }
1062         
1063         if (_wapi_handle_type (handle) == WAPI_HANDLE_UNUSED) {
1064                 g_warning ("%s: Attempting to unref unused handle %p",
1065                            __func__, handle);
1066                 return;
1067         }
1068
1069         /* Possible race condition here if another thread refs the
1070          * handle between here and setting the type to UNUSED.  I
1071          * could lock a mutex, but I'm not sure that allowing a handle
1072          * reference to reach 0 isn't an application bug anyway.
1073          */
1074         destroy = (InterlockedDecrement ((gint32 *)&_WAPI_PRIVATE_HANDLES(idx).ref) ==0);
1075         
1076 #ifdef DEBUG_REFS
1077         g_message ("%s: %s handle %p ref now %d (destroy %s)", __func__,
1078                    _wapi_handle_typename[_WAPI_PRIVATE_HANDLES (idx).type],
1079                    handle,
1080                    _WAPI_PRIVATE_HANDLES(idx).ref, destroy?"TRUE":"FALSE");
1081 #endif
1082         
1083         if(destroy==TRUE) {
1084                 /* Need to copy the handle info, reset the slot in the
1085                  * array, and _only then_ call the close function to
1086                  * avoid race conditions (eg file descriptors being
1087                  * closed, and another file being opened getting the
1088                  * same fd racing the memset())
1089                  */
1090                 struct _WapiHandleUnshared handle_data;
1091                 struct _WapiHandleShared shared_handle_data;
1092                 WapiHandleType type = _WAPI_PRIVATE_HANDLES(idx).type;
1093                 void (*close_func)(gpointer, gpointer) = _wapi_handle_ops_get_close_func (type);
1094                 gboolean is_shared = _WAPI_SHARED_HANDLE(type);
1095
1096                 if (is_shared) {
1097                         /* If this is a shared handle we need to take
1098                          * the shared lock outside of the scan_mutex
1099                          * lock to avoid deadlocks
1100                          */
1101                         thr_ret = _wapi_handle_lock_shared_handles ();
1102                         g_assert (thr_ret == 0);
1103                 }
1104                 
1105                 thr_ret = mono_mutex_lock (&scan_mutex);
1106
1107                 DEBUG ("%s: Destroying handle %p", __func__, handle);
1108                 
1109                 memcpy (&handle_data, &_WAPI_PRIVATE_HANDLES(idx),
1110                         sizeof (struct _WapiHandleUnshared));
1111
1112                 memset (&_WAPI_PRIVATE_HANDLES(idx).u, '\0',
1113                         sizeof(_WAPI_PRIVATE_HANDLES(idx).u));
1114
1115                 _WAPI_PRIVATE_HANDLES(idx).type = WAPI_HANDLE_UNUSED;
1116                 
1117                 if (!is_shared) {
1118                         /* Destroy the mutex and cond var.  We hope nobody
1119                          * tried to grab them between the handle unlock and
1120                          * now, but pthreads doesn't have a
1121                          * "unlock_and_destroy" atomic function.
1122                          */
1123                         thr_ret = mono_mutex_destroy (&_WAPI_PRIVATE_HANDLES(idx).signal_mutex);
1124                         /*WARNING gross hack to make cleanup not crash when exiting without the whole runtime teardown.*/
1125                         if (thr_ret == EBUSY && ignore_private_busy_handles) {
1126                                 early_exit = TRUE;
1127                         } else {
1128                                 if (thr_ret != 0)
1129                                         g_error ("Error destroying handle %p mutex due to %d\n", handle, thr_ret);
1130
1131                                 thr_ret = pthread_cond_destroy (&_WAPI_PRIVATE_HANDLES(idx).signal_cond);
1132                                 if (thr_ret == EBUSY && ignore_private_busy_handles)
1133                                         early_exit = TRUE;
1134                                 else if (thr_ret != 0)
1135                                         g_error ("Error destroying handle %p cond var due to %d\n", handle, thr_ret);
1136                         }
1137                 } else {
1138                         struct _WapiHandleShared *shared = &_wapi_shared_layout->handles[handle_data.u.shared.offset];
1139
1140                         memcpy (&shared_handle_data, shared,
1141                                 sizeof (struct _WapiHandleShared));
1142                         
1143                         /* It's possible that this handle is already
1144                          * pointing at a deleted shared section
1145                          */
1146 #ifdef DEBUG_REFS
1147                         g_message ("%s: %s handle %p shared refs before dec %d", __func__, _wapi_handle_typename[type], handle, shared->handle_refs);
1148 #endif
1149
1150                         if (shared->handle_refs > 0) {
1151                                 shared->handle_refs--;
1152                                 if (shared->handle_refs == 0) {
1153                                         memset (shared, '\0', sizeof (struct _WapiHandleShared));
1154                                 }
1155                         }
1156                 }
1157
1158                 thr_ret = mono_mutex_unlock (&scan_mutex);
1159                 g_assert (thr_ret == 0);
1160
1161                 if (early_exit)
1162                         return;
1163                 if (is_shared) {
1164                         _wapi_handle_unlock_shared_handles ();
1165                 }
1166                 
1167                 if (close_func != NULL) {
1168                         if (is_shared) {
1169                                 close_func (handle, &shared_handle_data.u);
1170                         } else {
1171                                 close_func (handle, &handle_data.u);
1172                         }
1173                 }
1174         }
1175 }
1176
1177 void _wapi_handle_unref (gpointer handle)
1178 {
1179         _wapi_handle_unref_full (handle, FALSE);
1180 }
1181
1182 void _wapi_handle_register_capabilities (WapiHandleType type,
1183                                          WapiHandleCapability caps)
1184 {
1185         handle_caps[type] = caps;
1186 }
1187
1188 gboolean _wapi_handle_test_capabilities (gpointer handle,
1189                                          WapiHandleCapability caps)
1190 {
1191         guint32 idx = GPOINTER_TO_UINT(handle);
1192         WapiHandleType type;
1193
1194         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1195                 return(FALSE);
1196         }
1197         
1198         type = _WAPI_PRIVATE_HANDLES(idx).type;
1199
1200         DEBUG ("%s: testing 0x%x against 0x%x (%d)", __func__,
1201                    handle_caps[type], caps, handle_caps[type] & caps);
1202         
1203         return((handle_caps[type] & caps) != 0);
1204 }
1205
1206 static void (*_wapi_handle_ops_get_close_func (WapiHandleType type))(gpointer, gpointer)
1207 {
1208         if (handle_ops[type] != NULL &&
1209             handle_ops[type]->close != NULL) {
1210                 return (handle_ops[type]->close);
1211         }
1212
1213         return (NULL);
1214 }
1215
1216 void _wapi_handle_ops_close (gpointer handle, gpointer data)
1217 {
1218         guint32 idx = GPOINTER_TO_UINT(handle);
1219         WapiHandleType type;
1220
1221         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1222                 return;
1223         }
1224         
1225         type = _WAPI_PRIVATE_HANDLES(idx).type;
1226
1227         if (handle_ops[type] != NULL &&
1228             handle_ops[type]->close != NULL) {
1229                 handle_ops[type]->close (handle, data);
1230         }
1231 }
1232
1233 void _wapi_handle_ops_signal (gpointer handle)
1234 {
1235         guint32 idx = GPOINTER_TO_UINT(handle);
1236         WapiHandleType type;
1237
1238         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1239                 return;
1240         }
1241         
1242         type = _WAPI_PRIVATE_HANDLES(idx).type;
1243
1244         if (handle_ops[type] != NULL && handle_ops[type]->signal != NULL) {
1245                 handle_ops[type]->signal (handle);
1246         }
1247 }
1248
1249 gboolean _wapi_handle_ops_own (gpointer handle)
1250 {
1251         guint32 idx = GPOINTER_TO_UINT(handle);
1252         WapiHandleType type;
1253         
1254         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1255                 return(FALSE);
1256         }
1257         
1258         type = _WAPI_PRIVATE_HANDLES(idx).type;
1259
1260         if (handle_ops[type] != NULL && handle_ops[type]->own_handle != NULL) {
1261                 return(handle_ops[type]->own_handle (handle));
1262         } else {
1263                 return(FALSE);
1264         }
1265 }
1266
1267 gboolean _wapi_handle_ops_isowned (gpointer handle)
1268 {
1269         guint32 idx = GPOINTER_TO_UINT(handle);
1270         WapiHandleType type;
1271
1272         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1273                 return(FALSE);
1274         }
1275         
1276         type = _WAPI_PRIVATE_HANDLES(idx).type;
1277
1278         if (handle_ops[type] != NULL && handle_ops[type]->is_owned != NULL) {
1279                 return(handle_ops[type]->is_owned (handle));
1280         } else {
1281                 return(FALSE);
1282         }
1283 }
1284
1285 guint32 _wapi_handle_ops_special_wait (gpointer handle, guint32 timeout, gboolean alertable)
1286 {
1287         guint32 idx = GPOINTER_TO_UINT(handle);
1288         WapiHandleType type;
1289         
1290         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1291                 return(WAIT_FAILED);
1292         }
1293         
1294         type = _WAPI_PRIVATE_HANDLES(idx).type;
1295         
1296         if (handle_ops[type] != NULL &&
1297             handle_ops[type]->special_wait != NULL) {
1298                 return(handle_ops[type]->special_wait (handle, timeout, alertable));
1299         } else {
1300                 return(WAIT_FAILED);
1301         }
1302 }
1303
1304 void _wapi_handle_ops_prewait (gpointer handle)
1305 {
1306         guint32 idx = GPOINTER_TO_UINT (handle);
1307         WapiHandleType type;
1308         
1309         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1310                 return;
1311         }
1312         
1313         type = _WAPI_PRIVATE_HANDLES (idx).type;
1314         
1315         if (handle_ops[type] != NULL &&
1316             handle_ops[type]->prewait != NULL) {
1317                 handle_ops[type]->prewait (handle);
1318         }
1319 }
1320
1321
1322 /**
1323  * CloseHandle:
1324  * @handle: The handle to release
1325  *
1326  * Closes and invalidates @handle, releasing any resources it
1327  * consumes.  When the last handle to a temporary or non-persistent
1328  * object is closed, that object can be deleted.  Closing the same
1329  * handle twice is an error.
1330  *
1331  * Return value: %TRUE on success, %FALSE otherwise.
1332  */
1333 gboolean CloseHandle(gpointer handle)
1334 {
1335         if (handle == NULL) {
1336                 /* Problem: because we map file descriptors to the
1337                  * same-numbered handle we can't tell the difference
1338                  * between a bogus handle and the handle to stdin.
1339                  * Assume that it's the console handle if that handle
1340                  * exists...
1341                  */
1342                 if (_WAPI_PRIVATE_HANDLES (0).type != WAPI_HANDLE_CONSOLE) {
1343                         SetLastError (ERROR_INVALID_PARAMETER);
1344                         return(FALSE);
1345                 }
1346         }
1347         if (handle == _WAPI_HANDLE_INVALID){
1348                 SetLastError (ERROR_INVALID_PARAMETER);
1349                 return(FALSE);
1350         }
1351         
1352         _wapi_handle_unref (handle);
1353         
1354         return(TRUE);
1355 }
1356
1357 /* Lots more to implement here, but this is all we need at the moment */
1358 gboolean DuplicateHandle (gpointer srcprocess, gpointer src,
1359                           gpointer targetprocess, gpointer *target,
1360                           guint32 access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUSED, guint32 options G_GNUC_UNUSED)
1361 {
1362         if (srcprocess != _WAPI_PROCESS_CURRENT ||
1363             targetprocess != _WAPI_PROCESS_CURRENT) {
1364                 /* Duplicating other process's handles is not supported */
1365                 SetLastError (ERROR_INVALID_HANDLE);
1366                 return(FALSE);
1367         }
1368         
1369         if (src == _WAPI_PROCESS_CURRENT) {
1370                 *target = _wapi_process_duplicate ();
1371         } else if (src == _WAPI_THREAD_CURRENT) {
1372                 g_assert_not_reached ();
1373         } else {
1374                 _wapi_handle_ref (src);
1375                 *target = src;
1376         }
1377         
1378         return(TRUE);
1379 }
1380
1381 gboolean _wapi_handle_count_signalled_handles (guint32 numhandles,
1382                                                gpointer *handles,
1383                                                gboolean waitall,
1384                                                guint32 *retcount,
1385                                                guint32 *lowest)
1386 {
1387         guint32 count, i, iter=0;
1388         gboolean ret;
1389         int thr_ret;
1390         WapiHandleType type;
1391         
1392         /* Lock all the handles, with backoff */
1393 again:
1394         thr_ret = _wapi_handle_lock_shared_handles ();
1395         g_assert (thr_ret == 0);
1396         
1397         for(i=0; i<numhandles; i++) {
1398                 gpointer handle = handles[i];
1399                 guint32 idx = GPOINTER_TO_UINT(handle);
1400
1401                 DEBUG ("%s: attempting to lock %p", __func__, handle);
1402
1403                 type = _WAPI_PRIVATE_HANDLES(idx).type;
1404
1405                 thr_ret = _wapi_handle_trylock_handle (handle);
1406                 
1407                 if (thr_ret != 0) {
1408                         /* Bummer */
1409                         
1410                         DEBUG ("%s: attempt failed for %p: %s", __func__,
1411                                    handle, strerror (thr_ret));
1412
1413                         thr_ret = _wapi_handle_unlock_shared_handles ();
1414                         g_assert (thr_ret == 0);
1415                         
1416                         while (i--) {
1417                                 handle = handles[i];
1418                                 idx = GPOINTER_TO_UINT(handle);
1419
1420                                 thr_ret = _wapi_handle_unlock_handle (handle);
1421                                 g_assert (thr_ret == 0);
1422                         }
1423
1424                         /* If iter ever reaches 100 the nanosleep will
1425                          * return EINVAL immediately, but we have a
1426                          * design flaw if that happens.
1427                          */
1428                         iter++;
1429                         if(iter==100) {
1430                                 g_warning ("%s: iteration overflow!",
1431                                            __func__);
1432                                 iter=1;
1433                         }
1434                         
1435                         DEBUG ("%s: Backing off for %d ms", __func__,
1436                                    iter*10);
1437                         _wapi_handle_spin (10 * iter);
1438                         
1439                         goto again;
1440                 }
1441         }
1442         
1443         DEBUG ("%s: Locked all handles", __func__);
1444
1445         count=0;
1446         *lowest=numhandles;
1447         
1448         for(i=0; i<numhandles; i++) {
1449                 gpointer handle = handles[i];
1450                 guint32 idx = GPOINTER_TO_UINT(handle);
1451                 
1452                 type = _WAPI_PRIVATE_HANDLES(idx).type;
1453
1454                 DEBUG ("%s: Checking handle %p", __func__, handle);
1455
1456                 if(((_wapi_handle_test_capabilities (handle, WAPI_HANDLE_CAP_OWN)==TRUE) &&
1457                     (_wapi_handle_ops_isowned (handle) == TRUE)) ||
1458                    (_WAPI_SHARED_HANDLE(type) &&
1459                     WAPI_SHARED_HANDLE_DATA(handle).signalled == TRUE) ||
1460                    (!_WAPI_SHARED_HANDLE(type) &&
1461                     _WAPI_PRIVATE_HANDLES(idx).signalled == TRUE)) {
1462                         count++;
1463                         
1464                         DEBUG ("%s: Handle %p signalled", __func__,
1465                                    handle);
1466                         if(*lowest>i) {
1467                                 *lowest=i;
1468                         }
1469                 }
1470         }
1471         
1472         DEBUG ("%s: %d event handles signalled", __func__, count);
1473
1474         if ((waitall == TRUE && count == numhandles) ||
1475             (waitall == FALSE && count > 0)) {
1476                 ret=TRUE;
1477         } else {
1478                 ret=FALSE;
1479         }
1480         
1481         DEBUG ("%s: Returning %d", __func__, ret);
1482
1483         *retcount=count;
1484         
1485         return(ret);
1486 }
1487
1488 void _wapi_handle_unlock_handles (guint32 numhandles, gpointer *handles)
1489 {
1490         guint32 i;
1491         int thr_ret;
1492         
1493         thr_ret = _wapi_handle_unlock_shared_handles ();
1494         g_assert (thr_ret == 0);
1495         
1496         for(i=0; i<numhandles; i++) {
1497                 gpointer handle = handles[i];
1498                 
1499                 DEBUG ("%s: unlocking handle %p", __func__, handle);
1500
1501                 thr_ret = _wapi_handle_unlock_handle (handle);
1502                 g_assert (thr_ret == 0);
1503         }
1504 }
1505
1506 static int timedwait_signal_poll_cond (pthread_cond_t *cond, mono_mutex_t *mutex, struct timespec *timeout, gboolean alertable)
1507 {
1508         struct timespec fake_timeout;
1509         int ret;
1510
1511         if (!alertable) {
1512                 if (timeout)
1513                         ret=mono_cond_timedwait (cond, mutex, timeout);
1514                 else
1515                         ret=mono_cond_wait (cond, mutex);
1516         } else {
1517                 _wapi_calc_timeout (&fake_timeout, 100);
1518         
1519                 if (timeout != NULL && ((fake_timeout.tv_sec > timeout->tv_sec) ||
1520                                                                 (fake_timeout.tv_sec == timeout->tv_sec &&
1521                                                                  fake_timeout.tv_nsec > timeout->tv_nsec))) {
1522                         /* Real timeout is less than 100ms time */
1523                         ret=mono_cond_timedwait (cond, mutex, timeout);
1524                 } else {
1525                         ret=mono_cond_timedwait (cond, mutex, &fake_timeout);
1526
1527                         /* Mask the fake timeout, this will cause
1528                          * another poll if the cond was not really signaled
1529                          */
1530                         if (ret==ETIMEDOUT) {
1531                                 ret=0;
1532                         }
1533                 }
1534         }
1535         
1536         return(ret);
1537 }
1538
1539 int _wapi_handle_wait_signal (gboolean poll)
1540 {
1541         return _wapi_handle_timedwait_signal_handle (_wapi_global_signal_handle, NULL, TRUE, poll);
1542 }
1543
1544 int _wapi_handle_timedwait_signal (struct timespec *timeout, gboolean poll)
1545 {
1546         return _wapi_handle_timedwait_signal_handle (_wapi_global_signal_handle, timeout, TRUE, poll);
1547 }
1548
1549 int _wapi_handle_wait_signal_handle (gpointer handle, gboolean alertable)
1550 {
1551         DEBUG ("%s: waiting for %p", __func__, handle);
1552         
1553         return _wapi_handle_timedwait_signal_handle (handle, NULL, alertable, FALSE);
1554 }
1555
1556 int _wapi_handle_timedwait_signal_handle (gpointer handle,
1557                                                                                   struct timespec *timeout, gboolean alertable, gboolean poll)
1558 {
1559         DEBUG ("%s: waiting for %p (type %s)", __func__, handle,
1560                    _wapi_handle_typename[_wapi_handle_type (handle)]);
1561         
1562         if (_WAPI_SHARED_HANDLE (_wapi_handle_type (handle))) {
1563                 if (WAPI_SHARED_HANDLE_DATA(handle).signalled == TRUE) {
1564                         return (0);
1565                 }
1566                 if (timeout != NULL) {
1567                         struct timespec fake_timeout;
1568                         _wapi_calc_timeout (&fake_timeout, 100);
1569                 
1570                         if ((fake_timeout.tv_sec > timeout->tv_sec) ||
1571                                 (fake_timeout.tv_sec == timeout->tv_sec &&
1572                                  fake_timeout.tv_nsec > timeout->tv_nsec)) {
1573                                 /* FIXME: Real timeout is less than
1574                                  * 100ms time, but is it really worth
1575                                  * calculating to the exact ms?
1576                                  */
1577                                 _wapi_handle_spin (100);
1578
1579                                 if (WAPI_SHARED_HANDLE_DATA(handle).signalled == TRUE) {
1580                                         return (0);
1581                                 } else {
1582                                         return (ETIMEDOUT);
1583                                 }
1584                         }
1585                 }
1586                 _wapi_handle_spin (100);
1587                 return (0);
1588                 
1589         } else {
1590                 guint32 idx = GPOINTER_TO_UINT(handle);
1591                 int res;
1592                 pthread_cond_t *cond;
1593                 mono_mutex_t *mutex;
1594
1595                 if (alertable && !wapi_thread_set_wait_handle (handle))
1596                         return 0;
1597
1598                 cond = &_WAPI_PRIVATE_HANDLES (idx).signal_cond;
1599                 mutex = &_WAPI_PRIVATE_HANDLES (idx).signal_mutex;
1600
1601                 if (poll) {
1602                         /* This is needed when waiting for process handles */
1603                         res = timedwait_signal_poll_cond (cond, mutex, timeout, alertable);
1604                 } else {
1605                         if (timeout)
1606                                 res = mono_cond_timedwait (cond, mutex, timeout);
1607                         else
1608                                 res = mono_cond_wait (cond, mutex);
1609                 }
1610
1611                 if (alertable)
1612                         wapi_thread_clear_wait_handle (handle);
1613
1614                 return res;
1615         }
1616 }
1617
1618 void
1619 _wapi_free_share_info (_WapiFileShare *share_info)
1620 {
1621         if (!_wapi_shm_enabled ()) {
1622                 file_share_hash_lock ();
1623                 g_hash_table_remove (file_share_hash, share_info);
1624                 file_share_hash_unlock ();
1625                 /* The hashtable dtor frees share_info */
1626         } else {
1627                 memset (share_info, '\0', sizeof(struct _WapiFileShare));
1628         }
1629 }
1630
1631 static gint
1632 wapi_share_info_equal (gconstpointer ka, gconstpointer kb)
1633 {
1634         const _WapiFileShare *s1 = ka;
1635         const _WapiFileShare *s2 = kb;
1636
1637         return (s1->device == s2->device && s1->inode == s2->inode) ? 1 : 0;
1638 }
1639
1640 static guint
1641 wapi_share_info_hash (gconstpointer data)
1642 {
1643         const _WapiFileShare *s = data;
1644
1645         return s->inode;
1646 }
1647
1648 gboolean _wapi_handle_get_or_set_share (guint64 device, guint64 inode,
1649                                         guint32 new_sharemode,
1650                                         guint32 new_access,
1651                                         guint32 *old_sharemode,
1652                                         guint32 *old_access,
1653                                         struct _WapiFileShare **share_info)
1654 {
1655         struct _WapiFileShare *file_share;
1656         guint32 now = (guint32)(time(NULL) & 0xFFFFFFFF);
1657         int thr_ret, i, first_unused = -1;
1658         gboolean exists = FALSE;
1659
1660         /* Prevents entries from expiring under us as we search
1661          */
1662         thr_ret = _wapi_handle_lock_shared_handles ();
1663         g_assert (thr_ret == 0);
1664         
1665         /* Prevent new entries racing with us */
1666         thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
1667         g_assert (thr_ret == 0);
1668
1669         if (!_wapi_shm_enabled ()) {
1670                 _WapiFileShare tmp;
1671
1672                 /*
1673                  * Instead of allocating a 4MB array, we use a hash table to keep track of this
1674                  * info. This is needed even if SHM is disabled, to track sharing inside
1675                  * the current process.
1676                  */
1677                 if (!file_share_hash) {
1678                         file_share_hash = g_hash_table_new_full (wapi_share_info_hash, wapi_share_info_equal, NULL, g_free);
1679                         mono_mutex_init_recursive (&file_share_hash_mutex);
1680                 }
1681                         
1682                 tmp.device = device;
1683                 tmp.inode = inode;
1684
1685                 file_share_hash_lock ();
1686
1687                 file_share = g_hash_table_lookup (file_share_hash, &tmp);
1688                 if (file_share) {
1689                         *old_sharemode = file_share->sharemode;
1690                         *old_access = file_share->access;
1691                         *share_info = file_share;
1692                         
1693                         InterlockedIncrement ((gint32 *)&file_share->handle_refs);
1694                         exists = TRUE;
1695                 } else {
1696                         file_share = g_new0 (_WapiFileShare, 1);
1697
1698                         file_share->device = device;
1699                         file_share->inode = inode;
1700                         file_share->opened_by_pid = _wapi_getpid ();
1701                         file_share->sharemode = new_sharemode;
1702                         file_share->access = new_access;
1703                         file_share->handle_refs = 1;
1704                         *share_info = file_share;
1705
1706                         g_hash_table_insert (file_share_hash, file_share, file_share);
1707                 }
1708
1709                 file_share_hash_unlock ();
1710         } else {
1711                 /* If a linear scan gets too slow we'll have to fit a hash
1712                  * table onto the shared mem backing store
1713                  */
1714                 *share_info = NULL;
1715                 for (i = 0; i <= _wapi_fileshare_layout->hwm; i++) {
1716                         file_share = &_wapi_fileshare_layout->share_info[i];
1717
1718                         /* Make a note of an unused slot, in case we need to
1719                          * store share info
1720                          */
1721                         if (first_unused == -1 && file_share->handle_refs == 0) {
1722                                 first_unused = i;
1723                                 continue;
1724                         }
1725                 
1726                         if (file_share->handle_refs == 0) {
1727                                 continue;
1728                         }
1729                 
1730                         if (file_share->device == device &&
1731                                 file_share->inode == inode) {
1732                                 *old_sharemode = file_share->sharemode;
1733                                 *old_access = file_share->access;
1734                                 *share_info = file_share;
1735                         
1736                                 /* Increment the reference count while we
1737                                  * still have sole access to the shared area.
1738                                  * This makes the increment atomic wrt
1739                                  * collections
1740                                  */
1741                                 InterlockedIncrement ((gint32 *)&file_share->handle_refs);
1742                         
1743                                 exists = TRUE;
1744                                 break;
1745                         }
1746                 }
1747         
1748                 if (!exists) {
1749                         if (i == _WAPI_FILESHARE_SIZE && first_unused == -1) {
1750                                 /* No more space */
1751                         } else {
1752                                 if (first_unused == -1) {
1753                                         file_share = &_wapi_fileshare_layout->share_info[++i];
1754                                         _wapi_fileshare_layout->hwm = i;
1755                                 } else {
1756                                         file_share = &_wapi_fileshare_layout->share_info[first_unused];
1757                                 }
1758                         
1759                                 file_share->device = device;
1760                                 file_share->inode = inode;
1761                                 file_share->opened_by_pid = _wapi_getpid ();
1762                                 file_share->sharemode = new_sharemode;
1763                                 file_share->access = new_access;
1764                                 file_share->handle_refs = 1;
1765                                 *share_info = file_share;
1766                         }
1767                 }
1768
1769                 if (*share_info != NULL) {
1770                         InterlockedExchange ((gint32 *)&(*share_info)->timestamp, now);
1771                 }
1772         }
1773         
1774         thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
1775
1776         _wapi_handle_unlock_shared_handles ();
1777
1778         return(exists);
1779 }
1780
1781 /* If we don't have the info in /proc, check if the process that
1782  * opened this share info is still there (it's not a perfect method,
1783  * due to pid reuse)
1784  */
1785 static void _wapi_handle_check_share_by_pid (struct _WapiFileShare *share_info)
1786 {
1787 #if defined(__native_client__)
1788         g_assert_not_reached ();
1789 #else
1790         if (kill (share_info->opened_by_pid, 0) == -1 &&
1791             (errno == ESRCH ||
1792              errno == EPERM)) {
1793                 /* It's gone completely (or there's a new process
1794                  * owned by someone else) so mark this share info as
1795                  * dead
1796                  */
1797                 DEBUG ("%s: Didn't find it, destroying entry", __func__);
1798
1799                 _wapi_free_share_info (share_info);
1800         }
1801 #endif
1802 }
1803
1804 #ifdef __linux__
1805 /* Scan /proc/<pids>/fd/ for open file descriptors to the file in
1806  * question.  If there are none, reset the share info.
1807  *
1808  * This implementation is Linux-specific; legacy systems will have to
1809  * implement their own ways of finding out if a particular file is
1810  * open by a process.
1811  */
1812 void _wapi_handle_check_share (struct _WapiFileShare *share_info, int fd)
1813 {
1814         gboolean found = FALSE, proc_fds = FALSE;
1815         int thr_ret, i;
1816         
1817         /* Prevents entries from expiring under us if we remove this
1818          * one
1819          */
1820         thr_ret = _wapi_handle_lock_shared_handles ();
1821         g_assert (thr_ret == 0);
1822         
1823         /* Prevent new entries racing with us */
1824         thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
1825         g_assert (thr_ret == 0);
1826         
1827         /* If there is no /proc, there's nothing more we can do here */
1828         if (access ("/proc", F_OK) == -1) {
1829                 _wapi_handle_check_share_by_pid (share_info);
1830                 goto done;
1831         }
1832
1833         /* If there's another handle that thinks it owns this fd, then even
1834          * if the fd has been closed behind our back consider it still owned.
1835          * See bugs 75764 and 75891
1836          */
1837         for (i = 0; i < _wapi_fd_reserve; i++) {
1838                 if (_wapi_private_handles [SLOT_INDEX (i)]) {
1839                         struct _WapiHandleUnshared *handle = &_WAPI_PRIVATE_HANDLES(i);
1840
1841                         if (i != fd &&
1842                                 handle->type == WAPI_HANDLE_FILE) {
1843                                 struct _WapiHandle_file *file_handle = &handle->u.file;
1844
1845                                 if (file_handle->share_info == share_info) {
1846                                         DEBUG ("%s: handle 0x%x has this file open!",
1847                                                            __func__, i);
1848
1849                                         goto done;
1850                                 }
1851                         }
1852                 }
1853         }
1854
1855         if (proc_fds == FALSE) {
1856                 _wapi_handle_check_share_by_pid (share_info);
1857         } else if (found == FALSE) {
1858                 /* Blank out this entry, as it is stale */
1859                 DEBUG ("%s: Didn't find it, destroying entry", __func__);
1860
1861                 _wapi_free_share_info (share_info);
1862         }
1863
1864 done:
1865         thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
1866
1867         _wapi_handle_unlock_shared_handles ();
1868 }
1869 #else
1870 //
1871 // Other implementations (non-Linux)
1872 //
1873 void _wapi_handle_check_share (struct _WapiFileShare *share_info, int fd)
1874 {
1875         int thr_ret;
1876         
1877         /* Prevents entries from expiring under us if we remove this
1878          * one */
1879         thr_ret = _wapi_handle_lock_shared_handles ();
1880         g_assert (thr_ret == 0);
1881         
1882         /* Prevent new entries racing with us */
1883         thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
1884         g_assert (thr_ret == 0);
1885         
1886         _wapi_handle_check_share_by_pid (share_info);
1887
1888         thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
1889         _wapi_handle_unlock_shared_handles ();
1890 }
1891 #endif
1892
1893 void _wapi_handle_dump (void)
1894 {
1895         struct _WapiHandleUnshared *handle_data;
1896         guint32 i, k;
1897         int thr_ret;
1898         
1899         thr_ret = mono_mutex_lock (&scan_mutex);
1900         g_assert (thr_ret == 0);
1901         
1902         for(i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) {
1903                 if (_wapi_private_handles [i]) {
1904                         for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
1905                                 handle_data = &_wapi_private_handles [i][k];
1906
1907                                 if (handle_data->type == WAPI_HANDLE_UNUSED) {
1908                                         continue;
1909                                 }
1910                 
1911                                 g_print ("%3x [%7s] %s %d ",
1912                                                  i * _WAPI_HANDLE_INITIAL_COUNT + k,
1913                                                  _wapi_handle_typename[handle_data->type],
1914                                                  handle_data->signalled?"Sg":"Un",
1915                                                  handle_data->ref);
1916                                 handle_details[handle_data->type](&handle_data->u);
1917                                 g_print ("\n");
1918                         }
1919                 }
1920         }
1921
1922         thr_ret = mono_mutex_unlock (&scan_mutex);
1923         g_assert (thr_ret == 0);
1924 }
1925
1926 static void _wapi_shared_details (gpointer handle_info)
1927 {
1928         struct _WapiHandle_shared_ref *shared = (struct _WapiHandle_shared_ref *)handle_info;
1929         
1930         g_print ("offset: 0x%x", shared->offset);
1931 }
1932
1933 void _wapi_handle_update_refs (void)
1934 {
1935         guint32 i, k;
1936         int thr_ret;
1937         guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
1938         
1939         thr_ret = _wapi_handle_lock_shared_handles ();
1940         g_assert (thr_ret == 0);
1941
1942         /* Prevent file share entries racing with us */
1943         thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
1944         g_assert(thr_ret == 0);
1945
1946         thr_ret = mono_mutex_lock (&scan_mutex);
1947         
1948         for(i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) {
1949                 if (_wapi_private_handles [i]) {
1950                         for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
1951                                 struct _WapiHandleUnshared *handle = &_wapi_private_handles [i][k];
1952
1953                                 if (_WAPI_SHARED_HANDLE(handle->type)) {
1954                                         struct _WapiHandleShared *shared_data;
1955                                 
1956                                         DEBUG ("%s: (%d) handle 0x%x is SHARED (%s)", __func__, _wapi_getpid (), i * _WAPI_HANDLE_INITIAL_COUNT + k, _wapi_handle_typename[handle->type]);
1957
1958                                         shared_data = &_wapi_shared_layout->handles[handle->u.shared.offset];
1959
1960                                         DEBUG ("%s: (%d) Updating timestamp of handle 0x%x", __func__, _wapi_getpid (), handle->u.shared.offset);
1961
1962                                         InterlockedExchange ((gint32 *)&shared_data->timestamp, now);
1963                                 } else if (handle->type == WAPI_HANDLE_FILE) {
1964                                         struct _WapiHandle_file *file_handle = &handle->u.file;
1965                                 
1966                                         DEBUG ("%s: (%d) handle 0x%x is FILE", __func__, _wapi_getpid (), i * _WAPI_HANDLE_INITIAL_COUNT + k);
1967                                 
1968                                         g_assert (file_handle->share_info != NULL);
1969
1970                                         DEBUG ("%s: (%d) Inc refs on fileshare 0x%x", __func__, _wapi_getpid (), (file_handle->share_info - &_wapi_fileshare_layout->share_info[0]) / sizeof(struct _WapiFileShare));
1971
1972                                         InterlockedExchange ((gint32 *)&file_handle->share_info->timestamp, now);
1973                                 }
1974                         }
1975                 }
1976         }
1977
1978         thr_ret = mono_mutex_unlock (&scan_mutex);
1979         g_assert (thr_ret == 0);
1980         
1981         thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
1982
1983         _wapi_handle_unlock_shared_handles ();
1984 }
1985