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