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