2009-05-26 Atsushi Enomoto <atsushi@ximian.com>
[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                         ref = _wapi_handle_new_shared (type, handle_specific);
482                         if (ref == 0) {
483                                 /* FIXME: grow the arrays */
484                                 handle = _WAPI_HANDLE_INVALID;
485                                 goto done;
486                         }
487                 }
488                 
489                 _WAPI_PRIVATE_HANDLES(handle_idx).u.shared.offset = ref;
490 #ifdef DEBUG
491                 g_message ("%s: New shared handle at offset 0x%x", __func__,
492                            ref);
493 #endif
494         }
495                 
496 done:
497         return(handle);
498 }
499
500 gpointer _wapi_handle_new (WapiHandleType type, gpointer handle_specific)
501 {
502         g_assert (_wapi_has_shut_down == FALSE);
503         
504         mono_once (&shared_init_once, shared_init);
505
506         return _wapi_handle_real_new (type, handle_specific);
507 }
508
509 gpointer _wapi_handle_new_from_offset (WapiHandleType type, guint32 offset,
510                                        gboolean timestamp)
511 {
512         guint32 handle_idx = 0;
513         gpointer handle = INVALID_HANDLE_VALUE;
514         int thr_ret, i, k;
515         struct _WapiHandleShared *shared;
516         guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
517         
518         g_assert (_wapi_has_shut_down == FALSE);
519         
520         mono_once (&shared_init_once, shared_init);
521
522 #ifdef DEBUG
523         g_message ("%s: Creating new handle of type %s to offset %d", __func__,
524                    _wapi_handle_typename[type], offset);
525 #endif
526
527         g_assert(!_WAPI_FD_HANDLE(type));
528         g_assert(_WAPI_SHARED_HANDLE(type));
529         g_assert(offset != 0);
530
531         shared = &_wapi_shared_layout->handles[offset];
532         if (timestamp) {
533                 /* Bump up the timestamp for this offset */
534                 InterlockedExchange ((gint32 *)&shared->timestamp, now);
535         }
536                 
537         pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
538                               (void *)&scan_mutex);
539         thr_ret = mono_mutex_lock (&scan_mutex);
540         g_assert (thr_ret == 0);
541
542         for (i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) {
543                 if (_wapi_private_handles [i]) {
544                         for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
545                                 struct _WapiHandleUnshared *handle_data = &_wapi_private_handles [i][k];
546                 
547                                 if (handle_data->type == type &&
548                                         handle_data->u.shared.offset == offset) {
549                                         handle = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
550                                         goto first_pass_done;
551                                 }
552                         }
553                 }
554         }
555
556 first_pass_done:
557         thr_ret = mono_mutex_unlock (&scan_mutex);
558         g_assert (thr_ret == 0);
559         pthread_cleanup_pop (0);
560
561         if (handle != INVALID_HANDLE_VALUE) {
562                 _wapi_handle_ref (handle);
563
564 #ifdef DEBUG
565                 g_message ("%s: Returning old handle %p referencing 0x%x",
566                            __func__, handle, offset);
567 #endif
568                 return (handle);
569         }
570
571         /* Prevent entries expiring under us as we search */
572         thr_ret = _wapi_handle_lock_shared_handles ();
573         g_assert (thr_ret == 0);
574         
575         if (shared->type == WAPI_HANDLE_UNUSED) {
576                 /* Someone deleted this handle while we were working */
577 #ifdef DEBUG
578                 g_message ("%s: Handle at 0x%x unused", __func__, offset);
579 #endif
580                 goto done;
581         }
582
583         if (shared->type != type) {
584 #ifdef DEBUG
585                 g_message ("%s: Wrong type at %d 0x%x! Found %s wanted %s",
586                            __func__, offset, offset,
587                            _wapi_handle_typename[shared->type],
588                            _wapi_handle_typename[type]);
589 #endif
590                 goto done;
591         }
592         
593         pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
594                               (void *)&scan_mutex);
595         thr_ret = mono_mutex_lock (&scan_mutex);
596         g_assert (thr_ret == 0);
597         
598         while ((handle_idx = _wapi_handle_new_internal (type, NULL)) == 0) {
599                 /* Try and expand the array, and have another go */
600                 int idx = SLOT_INDEX (_wapi_private_handle_count);
601                 _wapi_private_handles [idx] = g_new0 (struct _WapiHandleUnshared,
602                                                 _WAPI_HANDLE_INITIAL_COUNT);
603
604                 _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
605                 _wapi_private_handle_slot_count ++;
606         }
607                 
608         thr_ret = mono_mutex_unlock (&scan_mutex);
609         g_assert (thr_ret == 0);
610         pthread_cleanup_pop (0);
611                 
612         /* Make sure we left the space for fd mappings */
613         g_assert (handle_idx >= _wapi_fd_reserve);
614         
615         handle = GUINT_TO_POINTER (handle_idx);
616                 
617         _WAPI_PRIVATE_HANDLES(handle_idx).u.shared.offset = offset;
618         InterlockedIncrement ((gint32 *)&shared->handle_refs);
619         
620 #ifdef DEBUG
621         g_message ("%s: Allocated new handle %p referencing 0x%x (shared refs %d)", __func__, handle, offset, shared->handle_refs);
622 #endif
623         
624 done:
625         _wapi_handle_unlock_shared_handles ();
626
627         return(handle);
628 }
629
630 static void
631 init_handles_slot (int idx)
632 {
633         int thr_ret;
634
635         pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
636                                                   (void *)&scan_mutex);
637         thr_ret = mono_mutex_lock (&scan_mutex);
638         g_assert (thr_ret == 0);
639
640         if (_wapi_private_handles [idx] == NULL) {
641                 _wapi_private_handles [idx] = g_new0 (struct _WapiHandleUnshared,
642                                                                                           _WAPI_HANDLE_INITIAL_COUNT);
643                 g_assert (_wapi_private_handles [idx]);
644         }
645
646         thr_ret = mono_mutex_unlock (&scan_mutex);
647         g_assert (thr_ret == 0);
648         pthread_cleanup_pop (0);
649 }
650
651 gpointer _wapi_handle_new_fd (WapiHandleType type, int fd,
652                               gpointer handle_specific)
653 {
654         struct _WapiHandleUnshared *handle;
655         int thr_ret;
656         
657         g_assert (_wapi_has_shut_down == FALSE);
658         
659         mono_once (&shared_init_once, shared_init);
660         
661 #ifdef DEBUG
662         g_message ("%s: Creating new handle of type %s", __func__,
663                    _wapi_handle_typename[type]);
664 #endif
665         
666         g_assert(_WAPI_FD_HANDLE(type));
667         g_assert(!_WAPI_SHARED_HANDLE(type));
668         
669         if (fd >= _wapi_fd_reserve) {
670 #ifdef DEBUG
671                 g_message ("%s: fd %d is too big", __func__, fd);
672 #endif
673
674                 return(GUINT_TO_POINTER (_WAPI_HANDLE_INVALID));
675         }
676
677         /* Initialize the array entries on demand */
678         if (_wapi_private_handles [SLOT_INDEX (fd)] == NULL)
679                 init_handles_slot (SLOT_INDEX (fd));
680
681         handle = &_WAPI_PRIVATE_HANDLES(fd);
682         
683         if (handle->type != WAPI_HANDLE_UNUSED) {
684 #ifdef DEBUG
685                 g_message ("%s: fd %d is already in use!", __func__, fd);
686 #endif
687                 /* FIXME: clean up this handle?  We can't do anything
688                  * with the fd, cos thats the new one
689                  */
690         }
691
692 #ifdef DEBUG
693         g_message ("%s: Assigning new fd handle %d", __func__, fd);
694 #endif
695
696         /* Prevent file share entries racing with us, when the file
697          * handle is only half initialised
698          */
699         thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
700         g_assert(thr_ret == 0);
701
702         _wapi_handle_init (handle, type, handle_specific);
703
704         thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
705
706         return(GUINT_TO_POINTER(fd));
707 }
708
709 gboolean _wapi_lookup_handle (gpointer handle, WapiHandleType type,
710                               gpointer *handle_specific)
711 {
712         struct _WapiHandleUnshared *handle_data;
713         guint32 handle_idx = GPOINTER_TO_UINT(handle);
714
715         if (!_WAPI_PRIVATE_VALID_SLOT (handle_idx)) {
716                 return(FALSE);
717         }
718
719         /* Initialize the array entries on demand */
720         if (_wapi_private_handles [SLOT_INDEX (handle_idx)] == NULL)
721                 init_handles_slot (SLOT_INDEX (handle_idx));
722         
723         handle_data = &_WAPI_PRIVATE_HANDLES(handle_idx);
724         
725         if (handle_data->type != type) {
726                 return(FALSE);
727         }
728
729         if (handle_specific == NULL) {
730                 return(FALSE);
731         }
732         
733         if (_WAPI_SHARED_HANDLE(type)) {
734                 struct _WapiHandle_shared_ref *ref;
735                 struct _WapiHandleShared *shared_handle_data;
736                         
737                 ref = &handle_data->u.shared;
738                 shared_handle_data = &_wapi_shared_layout->handles[ref->offset];
739                 
740                 if (shared_handle_data->type != type) {
741                         /* The handle must have been deleted on us
742                          */
743                         return (FALSE);
744                 }
745                 
746                 *handle_specific = &shared_handle_data->u;
747         } else {
748                 *handle_specific = &handle_data->u;
749         }
750         
751         return(TRUE);
752 }
753
754 void
755 _wapi_handle_foreach (WapiHandleType type,
756                         gboolean (*on_each)(gpointer test, gpointer user),
757                         gpointer user_data)
758 {
759         struct _WapiHandleUnshared *handle_data = NULL;
760         gpointer ret = NULL;
761         guint32 i, k;
762         int thr_ret;
763
764         pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
765                               (void *)&scan_mutex);
766         thr_ret = mono_mutex_lock (&scan_mutex);
767         g_assert (thr_ret == 0);
768
769         for (i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) {
770                 if (_wapi_private_handles [i]) {
771                         for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
772                                 handle_data = &_wapi_private_handles [i][k];
773                         
774                                 if (handle_data->type == type) {
775                                         ret = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
776                                         if (on_each (ret, user_data) == TRUE)
777                                                 break;
778                                 }
779                         }
780                 }
781         }
782
783         thr_ret = mono_mutex_unlock (&scan_mutex);
784         g_assert (thr_ret == 0);
785         pthread_cleanup_pop (0);
786 }
787
788 /* This might list some shared handles twice if they are already
789  * opened by this process, and the check function returns FALSE the
790  * first time.  Shared handles that are created during the search are
791  * unreffed if the check function returns FALSE, so callers must not
792  * rely on the handle persisting (unless the check function returns
793  * TRUE)
794  */
795 gpointer _wapi_search_handle (WapiHandleType type,
796                               gboolean (*check)(gpointer test, gpointer user),
797                               gpointer user_data,
798                               gpointer *handle_specific,
799                               gboolean search_shared)
800 {
801         struct _WapiHandleUnshared *handle_data = NULL;
802         struct _WapiHandleShared *shared = NULL;
803         gpointer ret = NULL;
804         guint32 i, k;
805         gboolean found = FALSE;
806         int thr_ret;
807
808         pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
809                               (void *)&scan_mutex);
810         thr_ret = mono_mutex_lock (&scan_mutex);
811         g_assert (thr_ret == 0);
812         
813         for (i = SLOT_INDEX (0); !found && i < _wapi_private_handle_slot_count; i++) {
814                 if (_wapi_private_handles [i]) {
815                         for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
816                                 handle_data = &_wapi_private_handles [i][k];
817                 
818                                 if (handle_data->type == type) {
819                                         ret = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
820                                         if (check (ret, user_data) == TRUE) {
821                                                 _wapi_handle_ref (ret);
822                                                 found = TRUE;
823
824                                                 if (_WAPI_SHARED_HANDLE (type)) {
825                                                         shared = &_wapi_shared_layout->handles[i];
826                                                 }
827                                         
828                                                 break;
829                                         }
830                                 }
831                         }
832                 }
833         }
834
835         thr_ret = mono_mutex_unlock (&scan_mutex);
836         g_assert (thr_ret == 0);
837         pthread_cleanup_pop (0);
838
839         if (!found && search_shared && _WAPI_SHARED_HANDLE (type)) {
840                 /* Not found yet, so search the shared memory too */
841 #ifdef DEBUG
842                 g_message ("%s: Looking at other shared handles...", __func__);
843 #endif
844
845                 for (i = 0; i < _WAPI_HANDLE_INITIAL_COUNT; i++) {
846                         shared = &_wapi_shared_layout->handles[i];
847                         
848                         if (shared->type == type) {
849                                 /* Tell new_from_offset to not
850                                  * timestamp this handle, because
851                                  * otherwise it will ping every handle
852                                  * in the list and they will never
853                                  * expire
854                                  */
855                                 ret = _wapi_handle_new_from_offset (type, i,
856                                                                     FALSE);
857                                 if (ret == INVALID_HANDLE_VALUE) {
858                                         /* This handle was deleted
859                                          * while we were looking at it
860                                          */
861                                         continue;
862                                 }
863                                 
864 #ifdef DEBUG
865                                 g_message ("%s: Opened tmp handle %p (type %s) from offset %d", __func__, ret, _wapi_handle_typename[type], i);
866 #endif
867
868                                 /* It's possible that the shared part
869                                  * of this handle has now been blown
870                                  * away (after new_from_offset
871                                  * successfully opened it,) if its
872                                  * timestamp is too old.  The check
873                                  * function needs to be aware of this,
874                                  * and cope if the handle has
875                                  * vanished.
876                                  */
877                                 if (check (ret, user_data) == TRUE) {
878                                         /* Timestamp this handle, but make
879                                          * sure it still exists first
880                                          */
881                                         thr_ret = _wapi_handle_lock_shared_handles ();
882                                         g_assert (thr_ret == 0);
883                                         
884                                         if (shared->type == type) {
885                                                 guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
886                                                 InterlockedExchange ((gint32 *)&shared->timestamp, now);
887
888                                                 found = TRUE;
889                                                 handle_data = &_WAPI_PRIVATE_HANDLES(GPOINTER_TO_UINT(ret));
890                                         
891                                                 _wapi_handle_unlock_shared_handles ();
892                                                 break;
893                                         } else {
894                                                 /* It's been deleted,
895                                                  * so just keep
896                                                  * looking
897                                                  */
898                                                 _wapi_handle_unlock_shared_handles ();
899                                         }
900                                 }
901                                 
902                                 /* This isn't the handle we're looking
903                                  * for, so drop the reference we took
904                                  * in _wapi_handle_new_from_offset ()
905                                  */
906                                 _wapi_handle_unref (ret);
907                         }
908                 }
909         }
910         
911         if (!found) {
912                 ret = NULL;
913                 goto done;
914         }
915         
916         if(handle_specific != NULL) {
917                 if (_WAPI_SHARED_HANDLE(type)) {
918                         g_assert(shared->type == type);
919                         
920                         *handle_specific = &shared->u;
921                 } else {
922                         *handle_specific = &handle_data->u;
923                 }
924         }
925
926 done:
927         return(ret);
928 }
929
930 /* Returns the offset of the metadata array, or -1 on error, or 0 for
931  * not found (0 is not a valid offset)
932  */
933 gint32 _wapi_search_handle_namespace (WapiHandleType type,
934                                       gchar *utf8_name)
935 {
936         struct _WapiHandleShared *shared_handle_data;
937         guint32 i;
938         gint32 ret = 0;
939         int thr_ret;
940         
941         g_assert(_WAPI_SHARED_HANDLE(type));
942         
943 #ifdef DEBUG
944         g_message ("%s: Lookup for handle named [%s] type %s", __func__,
945                    utf8_name, _wapi_handle_typename[type]);
946 #endif
947
948         /* Do a handle collection before starting to look, so that any
949          * stale cruft gets removed
950          */
951         _wapi_handle_collect ();
952         
953         thr_ret = _wapi_handle_lock_shared_handles ();
954         g_assert (thr_ret == 0);
955         
956         for(i = 1; i < _WAPI_HANDLE_INITIAL_COUNT; i++) {
957                 WapiSharedNamespace *sharedns;
958                 
959                 shared_handle_data = &_wapi_shared_layout->handles[i];
960
961                 /* Check mutex, event, semaphore, timer, job and
962                  * file-mapping object names.  So far only mutex,
963                  * semaphore and event are implemented.
964                  */
965                 if (!_WAPI_SHARED_NAMESPACE (shared_handle_data->type)) {
966                         continue;
967                 }
968
969 #ifdef DEBUG
970                 g_message ("%s: found a shared namespace handle at 0x%x (type %s)", __func__, i, _wapi_handle_typename[shared_handle_data->type]);
971 #endif
972
973                 sharedns=(WapiSharedNamespace *)&shared_handle_data->u;
974                         
975 #ifdef DEBUG
976                 g_message ("%s: name is [%s]", __func__, sharedns->name);
977 #endif
978
979                 if (strcmp (sharedns->name, utf8_name) == 0) {
980                         if (shared_handle_data->type != type) {
981                                 /* Its the wrong type, so fail now */
982 #ifdef DEBUG
983                                 g_message ("%s: handle 0x%x matches name but is wrong type: %s", __func__, i, _wapi_handle_typename[shared_handle_data->type]);
984 #endif
985                                 ret = -1;
986                                 goto done;
987                         } else {
988 #ifdef DEBUG
989                                 g_message ("%s: handle 0x%x matches name and type", __func__, i);
990 #endif
991                                 ret = i;
992                                 goto done;
993                         }
994                 }
995         }
996
997 done:
998         _wapi_handle_unlock_shared_handles ();
999         
1000         return(ret);
1001 }
1002
1003 void _wapi_handle_ref (gpointer handle)
1004 {
1005         guint32 idx = GPOINTER_TO_UINT(handle);
1006         guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
1007         struct _WapiHandleUnshared *handle_data;
1008
1009         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1010                 return;
1011         }
1012         
1013         if (_wapi_handle_type (handle) == WAPI_HANDLE_UNUSED) {
1014                 g_warning ("%s: Attempting to ref unused handle %p", __func__,
1015                            handle);
1016                 return;
1017         }
1018
1019         handle_data = &_WAPI_PRIVATE_HANDLES(idx);
1020         
1021         InterlockedIncrement ((gint32 *)&handle_data->ref);
1022
1023         /* It's possible for processes to exit before getting around
1024          * to updating timestamps in the collection thread, so if a
1025          * shared handle is reffed do the timestamp here as well just
1026          * to make sure.
1027          */
1028         if (_WAPI_SHARED_HANDLE(handle_data->type)) {
1029                 struct _WapiHandleShared *shared_data = &_wapi_shared_layout->handles[handle_data->u.shared.offset];
1030                 
1031                 InterlockedExchange ((gint32 *)&shared_data->timestamp, now);
1032         }
1033         
1034 #ifdef DEBUG_REFS
1035         g_message ("%s: %s handle %p ref now %d", __func__, 
1036                    _wapi_handle_typename[_WAPI_PRIVATE_HANDLES (idx).type],
1037                    handle,
1038                    _WAPI_PRIVATE_HANDLES(idx).ref);
1039 #endif
1040 }
1041
1042 /* The handle must not be locked on entry to this function */
1043 void _wapi_handle_unref (gpointer handle)
1044 {
1045         guint32 idx = GPOINTER_TO_UINT(handle);
1046         gboolean destroy = FALSE;
1047         int thr_ret;
1048
1049         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1050                 return;
1051         }
1052         
1053         if (_wapi_handle_type (handle) == WAPI_HANDLE_UNUSED) {
1054                 g_warning ("%s: Attempting to unref unused handle %p",
1055                            __func__, handle);
1056                 return;
1057         }
1058
1059         /* Possible race condition here if another thread refs the
1060          * handle between here and setting the type to UNUSED.  I
1061          * could lock a mutex, but I'm not sure that allowing a handle
1062          * reference to reach 0 isn't an application bug anyway.
1063          */
1064         destroy = (InterlockedDecrement ((gint32 *)&_WAPI_PRIVATE_HANDLES(idx).ref) ==0);
1065         
1066 #ifdef DEBUG_REFS
1067         g_message ("%s: %s handle %p ref now %d (destroy %s)", __func__,
1068                    _wapi_handle_typename[_WAPI_PRIVATE_HANDLES (idx).type],
1069                    handle,
1070                    _WAPI_PRIVATE_HANDLES(idx).ref, destroy?"TRUE":"FALSE");
1071 #endif
1072         
1073         if(destroy==TRUE) {
1074                 /* Need to copy the handle info, reset the slot in the
1075                  * array, and _only then_ call the close function to
1076                  * avoid race conditions (eg file descriptors being
1077                  * closed, and another file being opened getting the
1078                  * same fd racing the memset())
1079                  */
1080                 struct _WapiHandleUnshared handle_data;
1081                 struct _WapiHandleShared shared_handle_data;
1082                 WapiHandleType type = _WAPI_PRIVATE_HANDLES(idx).type;
1083                 void (*close_func)(gpointer, gpointer) = _wapi_handle_ops_get_close_func (type);
1084                 gboolean is_shared = _WAPI_SHARED_HANDLE(type);
1085
1086                 if (is_shared) {
1087                         /* If this is a shared handle we need to take
1088                          * the shared lock outside of the scan_mutex
1089                          * lock to avoid deadlocks
1090                          */
1091                         thr_ret = _wapi_handle_lock_shared_handles ();
1092                         g_assert (thr_ret == 0);
1093                 }
1094                 
1095                 pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup, (void *)&scan_mutex);
1096                 thr_ret = mono_mutex_lock (&scan_mutex);
1097
1098 #ifdef DEBUG
1099                 g_message ("%s: Destroying handle %p", __func__, handle);
1100 #endif
1101                 
1102                 memcpy (&handle_data, &_WAPI_PRIVATE_HANDLES(idx),
1103                         sizeof (struct _WapiHandleUnshared));
1104
1105                 memset (&_WAPI_PRIVATE_HANDLES(idx).u, '\0',
1106                         sizeof(_WAPI_PRIVATE_HANDLES(idx).u));
1107
1108                 _WAPI_PRIVATE_HANDLES(idx).type = WAPI_HANDLE_UNUSED;
1109                 
1110                 if (!is_shared) {
1111                         /* Destroy the mutex and cond var.  We hope nobody
1112                          * tried to grab them between the handle unlock and
1113                          * now, but pthreads doesn't have a
1114                          * "unlock_and_destroy" atomic function.
1115                          */
1116                         thr_ret = mono_mutex_destroy (&_WAPI_PRIVATE_HANDLES(idx).signal_mutex);
1117                         g_assert (thr_ret == 0);
1118                                 
1119                         thr_ret = pthread_cond_destroy (&_WAPI_PRIVATE_HANDLES(idx).signal_cond);
1120                         g_assert (thr_ret == 0);
1121                 } else {
1122                         struct _WapiHandleShared *shared = &_wapi_shared_layout->handles[handle_data.u.shared.offset];
1123
1124                         memcpy (&shared_handle_data, shared,
1125                                 sizeof (struct _WapiHandleShared));
1126                         
1127                         /* It's possible that this handle is already
1128                          * pointing at a deleted shared section
1129                          */
1130 #ifdef DEBUG_REFS
1131                         g_message ("%s: %s handle %p shared refs before dec %d", __func__, _wapi_handle_typename[type], handle, shared->handle_refs);
1132 #endif
1133
1134                         if (shared->handle_refs > 0) {
1135                                 shared->handle_refs--;
1136                                 if (shared->handle_refs == 0) {
1137                                         memset (shared, '\0', sizeof (struct _WapiHandleShared));
1138                                 }
1139                         }
1140                 }
1141
1142                 thr_ret = mono_mutex_unlock (&scan_mutex);
1143                 g_assert (thr_ret == 0);
1144                 pthread_cleanup_pop (0);
1145
1146                 if (is_shared) {
1147                         _wapi_handle_unlock_shared_handles ();
1148                 }
1149                 
1150                 if (close_func != NULL) {
1151                         if (is_shared) {
1152                                 close_func (handle, &shared_handle_data.u);
1153                         } else {
1154                                 close_func (handle, &handle_data.u);
1155                         }
1156                 }
1157         }
1158 }
1159
1160 void _wapi_handle_register_capabilities (WapiHandleType type,
1161                                          WapiHandleCapability caps)
1162 {
1163         handle_caps[type] = caps;
1164 }
1165
1166 gboolean _wapi_handle_test_capabilities (gpointer handle,
1167                                          WapiHandleCapability caps)
1168 {
1169         guint32 idx = GPOINTER_TO_UINT(handle);
1170         WapiHandleType type;
1171
1172         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1173                 return(FALSE);
1174         }
1175         
1176         type = _WAPI_PRIVATE_HANDLES(idx).type;
1177
1178 #ifdef DEBUG
1179         g_message ("%s: testing 0x%x against 0x%x (%d)", __func__,
1180                    handle_caps[type], caps, handle_caps[type] & caps);
1181 #endif
1182         
1183         return((handle_caps[type] & caps) != 0);
1184 }
1185
1186 static void (*_wapi_handle_ops_get_close_func (WapiHandleType type))(gpointer, gpointer)
1187 {
1188         if (handle_ops[type] != NULL &&
1189             handle_ops[type]->close != NULL) {
1190                 return (handle_ops[type]->close);
1191         }
1192
1193         return (NULL);
1194 }
1195
1196 void _wapi_handle_ops_close (gpointer handle, gpointer data)
1197 {
1198         guint32 idx = GPOINTER_TO_UINT(handle);
1199         WapiHandleType type;
1200
1201         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1202                 return;
1203         }
1204         
1205         type = _WAPI_PRIVATE_HANDLES(idx).type;
1206
1207         if (handle_ops[type] != NULL &&
1208             handle_ops[type]->close != NULL) {
1209                 handle_ops[type]->close (handle, data);
1210         }
1211 }
1212
1213 void _wapi_handle_ops_signal (gpointer handle)
1214 {
1215         guint32 idx = GPOINTER_TO_UINT(handle);
1216         WapiHandleType type;
1217
1218         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1219                 return;
1220         }
1221         
1222         type = _WAPI_PRIVATE_HANDLES(idx).type;
1223
1224         if (handle_ops[type] != NULL && handle_ops[type]->signal != NULL) {
1225                 handle_ops[type]->signal (handle);
1226         }
1227 }
1228
1229 gboolean _wapi_handle_ops_own (gpointer handle)
1230 {
1231         guint32 idx = GPOINTER_TO_UINT(handle);
1232         WapiHandleType type;
1233         
1234         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1235                 return(FALSE);
1236         }
1237         
1238         type = _WAPI_PRIVATE_HANDLES(idx).type;
1239
1240         if (handle_ops[type] != NULL && handle_ops[type]->own_handle != NULL) {
1241                 return(handle_ops[type]->own_handle (handle));
1242         } else {
1243                 return(FALSE);
1244         }
1245 }
1246
1247 gboolean _wapi_handle_ops_isowned (gpointer handle)
1248 {
1249         guint32 idx = GPOINTER_TO_UINT(handle);
1250         WapiHandleType type;
1251
1252         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1253                 return(FALSE);
1254         }
1255         
1256         type = _WAPI_PRIVATE_HANDLES(idx).type;
1257
1258         if (handle_ops[type] != NULL && handle_ops[type]->is_owned != NULL) {
1259                 return(handle_ops[type]->is_owned (handle));
1260         } else {
1261                 return(FALSE);
1262         }
1263 }
1264
1265 guint32 _wapi_handle_ops_special_wait (gpointer handle, guint32 timeout)
1266 {
1267         guint32 idx = GPOINTER_TO_UINT(handle);
1268         WapiHandleType type;
1269         
1270         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1271                 return(WAIT_FAILED);
1272         }
1273         
1274         type = _WAPI_PRIVATE_HANDLES(idx).type;
1275         
1276         if (handle_ops[type] != NULL &&
1277             handle_ops[type]->special_wait != NULL) {
1278                 return(handle_ops[type]->special_wait (handle, timeout));
1279         } else {
1280                 return(WAIT_FAILED);
1281         }
1282 }
1283
1284 void _wapi_handle_ops_prewait (gpointer handle)
1285 {
1286         guint32 idx = GPOINTER_TO_UINT (handle);
1287         WapiHandleType type;
1288         
1289         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1290                 return;
1291         }
1292         
1293         type = _WAPI_PRIVATE_HANDLES (idx).type;
1294         
1295         if (handle_ops[type] != NULL &&
1296             handle_ops[type]->prewait != NULL) {
1297                 handle_ops[type]->prewait (handle);
1298         }
1299 }
1300
1301
1302 /**
1303  * CloseHandle:
1304  * @handle: The handle to release
1305  *
1306  * Closes and invalidates @handle, releasing any resources it
1307  * consumes.  When the last handle to a temporary or non-persistent
1308  * object is closed, that object can be deleted.  Closing the same
1309  * handle twice is an error.
1310  *
1311  * Return value: %TRUE on success, %FALSE otherwise.
1312  */
1313 gboolean CloseHandle(gpointer handle)
1314 {
1315         if (handle == NULL) {
1316                 /* Problem: because we map file descriptors to the
1317                  * same-numbered handle we can't tell the difference
1318                  * between a bogus handle and the handle to stdin.
1319                  * Assume that it's the console handle if that handle
1320                  * exists...
1321                  */
1322                 if (_WAPI_PRIVATE_HANDLES (0).type != WAPI_HANDLE_CONSOLE) {
1323                         SetLastError (ERROR_INVALID_PARAMETER);
1324                         return(FALSE);
1325                 }
1326         }
1327         if (handle == _WAPI_HANDLE_INVALID){
1328                 SetLastError (ERROR_INVALID_PARAMETER);
1329                 return(FALSE);
1330         }
1331         
1332         _wapi_handle_unref (handle);
1333         
1334         return(TRUE);
1335 }
1336
1337 /* Lots more to implement here, but this is all we need at the moment */
1338 gboolean DuplicateHandle (gpointer srcprocess, gpointer src,
1339                           gpointer targetprocess, gpointer *target,
1340                           guint32 access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUSED, guint32 options G_GNUC_UNUSED)
1341 {
1342         if (srcprocess != _WAPI_PROCESS_CURRENT ||
1343             targetprocess != _WAPI_PROCESS_CURRENT) {
1344                 /* Duplicating other process's handles is not supported */
1345                 SetLastError (ERROR_INVALID_HANDLE);
1346                 return(FALSE);
1347         }
1348         
1349         if (src == _WAPI_PROCESS_CURRENT) {
1350                 *target = _wapi_process_duplicate ();
1351         } else if (src == _WAPI_THREAD_CURRENT) {
1352                 *target = _wapi_thread_duplicate ();
1353         } else {
1354                 _wapi_handle_ref (src);
1355                 *target = src;
1356         }
1357         
1358         return(TRUE);
1359 }
1360
1361 gboolean _wapi_handle_count_signalled_handles (guint32 numhandles,
1362                                                gpointer *handles,
1363                                                gboolean waitall,
1364                                                guint32 *retcount,
1365                                                guint32 *lowest)
1366 {
1367         guint32 count, i, iter=0;
1368         gboolean ret;
1369         int thr_ret;
1370         WapiHandleType type;
1371         
1372         /* Lock all the handles, with backoff */
1373 again:
1374         thr_ret = _wapi_handle_lock_shared_handles ();
1375         g_assert (thr_ret == 0);
1376         
1377         for(i=0; i<numhandles; i++) {
1378                 gpointer handle = handles[i];
1379                 guint32 idx = GPOINTER_TO_UINT(handle);
1380
1381 #ifdef DEBUG
1382                 g_message ("%s: attempting to lock %p", __func__, handle);
1383 #endif
1384
1385                 type = _WAPI_PRIVATE_HANDLES(idx).type;
1386
1387                 thr_ret = _wapi_handle_trylock_handle (handle);
1388                 
1389                 if (thr_ret != 0) {
1390                         /* Bummer */
1391                         
1392 #ifdef DEBUG
1393                         g_message ("%s: attempt failed for %p: %s", __func__,
1394                                    handle, strerror (thr_ret));
1395 #endif
1396
1397                         thr_ret = _wapi_handle_unlock_shared_handles ();
1398                         g_assert (thr_ret == 0);
1399                         
1400                         while (i--) {
1401                                 handle = handles[i];
1402                                 idx = GPOINTER_TO_UINT(handle);
1403
1404                                 thr_ret = _wapi_handle_unlock_handle (handle);
1405                                 g_assert (thr_ret == 0);
1406                         }
1407
1408                         /* If iter ever reaches 100 the nanosleep will
1409                          * return EINVAL immediately, but we have a
1410                          * design flaw if that happens.
1411                          */
1412                         iter++;
1413                         if(iter==100) {
1414                                 g_warning ("%s: iteration overflow!",
1415                                            __func__);
1416                                 iter=1;
1417                         }
1418                         
1419 #ifdef DEBUG
1420                         g_message ("%s: Backing off for %d ms", __func__,
1421                                    iter*10);
1422 #endif
1423                         _wapi_handle_spin (10 * iter);
1424                         
1425                         goto again;
1426                 }
1427         }
1428         
1429 #ifdef DEBUG
1430         g_message ("%s: Locked all handles", __func__);
1431 #endif
1432
1433         count=0;
1434         *lowest=numhandles;
1435         
1436         for(i=0; i<numhandles; i++) {
1437                 gpointer handle = handles[i];
1438                 guint32 idx = GPOINTER_TO_UINT(handle);
1439                 
1440                 type = _WAPI_PRIVATE_HANDLES(idx).type;
1441
1442 #ifdef DEBUG
1443                 g_message ("%s: Checking handle %p", __func__, handle);
1444 #endif
1445
1446                 if(((_wapi_handle_test_capabilities (handle, WAPI_HANDLE_CAP_OWN)==TRUE) &&
1447                     (_wapi_handle_ops_isowned (handle) == TRUE)) ||
1448                    (_WAPI_SHARED_HANDLE(type) &&
1449                     WAPI_SHARED_HANDLE_DATA(handle).signalled == TRUE) ||
1450                    (!_WAPI_SHARED_HANDLE(type) &&
1451                     _WAPI_PRIVATE_HANDLES(idx).signalled == TRUE)) {
1452                         count++;
1453                         
1454 #ifdef DEBUG
1455                         g_message ("%s: Handle %p signalled", __func__,
1456                                    handle);
1457 #endif
1458                         if(*lowest>i) {
1459                                 *lowest=i;
1460                         }
1461                 }
1462         }
1463         
1464 #ifdef DEBUG
1465         g_message ("%s: %d event handles signalled", __func__, count);
1466 #endif
1467
1468         if ((waitall == TRUE && count == numhandles) ||
1469             (waitall == FALSE && count > 0)) {
1470                 ret=TRUE;
1471         } else {
1472                 ret=FALSE;
1473         }
1474         
1475 #ifdef DEBUG
1476         g_message ("%s: Returning %d", __func__, ret);
1477 #endif
1478
1479         *retcount=count;
1480         
1481         return(ret);
1482 }
1483
1484 void _wapi_handle_unlock_handles (guint32 numhandles, gpointer *handles)
1485 {
1486         guint32 i;
1487         int thr_ret;
1488         
1489         thr_ret = _wapi_handle_unlock_shared_handles ();
1490         g_assert (thr_ret == 0);
1491         
1492         for(i=0; i<numhandles; i++) {
1493                 gpointer handle = handles[i];
1494                 
1495 #ifdef DEBUG
1496                 g_message ("%s: unlocking handle %p", __func__, handle);
1497 #endif
1498
1499                 thr_ret = _wapi_handle_unlock_handle (handle);
1500                 g_assert (thr_ret == 0);
1501         }
1502 }
1503
1504 static int timedwait_signal_poll_cond (pthread_cond_t *cond, mono_mutex_t *mutex, struct timespec *timeout, gboolean alertable)
1505 {
1506         struct timespec fake_timeout;
1507         int ret;
1508
1509         if (!alertable) {
1510                 if (timeout)
1511                         ret=mono_cond_timedwait (cond, mutex, timeout);
1512                 else
1513                         ret=mono_cond_wait (cond, mutex);
1514         } else {
1515                 _wapi_calc_timeout (&fake_timeout, 100);
1516         
1517                 if (timeout != NULL && ((fake_timeout.tv_sec > timeout->tv_sec) ||
1518                                                                 (fake_timeout.tv_sec == timeout->tv_sec &&
1519                                                                  fake_timeout.tv_nsec > timeout->tv_nsec))) {
1520                         /* Real timeout is less than 100ms time */
1521                         ret=mono_cond_timedwait (cond, mutex, timeout);
1522                 } else {
1523                         ret=mono_cond_timedwait (cond, mutex, &fake_timeout);
1524
1525                         /* Mask the fake timeout, this will cause
1526                          * another poll if the cond was not really signaled
1527                          */
1528                         if (ret==ETIMEDOUT) {
1529                                 ret=0;
1530                         }
1531                 }
1532         }
1533         
1534         return(ret);
1535 }
1536
1537 int _wapi_handle_wait_signal (gboolean poll)
1538 {
1539         return _wapi_handle_timedwait_signal_handle (_wapi_global_signal_handle, NULL, TRUE, poll);
1540 }
1541
1542 int _wapi_handle_timedwait_signal (struct timespec *timeout, gboolean poll)
1543 {
1544         return _wapi_handle_timedwait_signal_handle (_wapi_global_signal_handle, timeout, TRUE, poll);
1545 }
1546
1547 int _wapi_handle_wait_signal_handle (gpointer handle, gboolean alertable)
1548 {
1549 #ifdef DEBUG
1550         g_message ("%s: waiting for %p", __func__, handle);
1551 #endif
1552         
1553         return _wapi_handle_timedwait_signal_handle (handle, NULL, alertable, FALSE);
1554 }
1555
1556 int _wapi_handle_timedwait_signal_handle (gpointer handle,
1557                                                                                   struct timespec *timeout, gboolean alertable, gboolean poll)
1558 {
1559 #ifdef DEBUG
1560         g_message ("%s: waiting for %p (type %s)", __func__, handle,
1561                    _wapi_handle_typename[_wapi_handle_type (handle)]);
1562 #endif
1563         
1564         if (_WAPI_SHARED_HANDLE (_wapi_handle_type (handle))) {
1565                 if (WAPI_SHARED_HANDLE_DATA(handle).signalled == TRUE) {
1566                         return (0);
1567                 }
1568                 if (timeout != NULL) {
1569                         struct timespec fake_timeout;
1570                         _wapi_calc_timeout (&fake_timeout, 100);
1571                 
1572                         if ((fake_timeout.tv_sec > timeout->tv_sec) ||
1573                                 (fake_timeout.tv_sec == timeout->tv_sec &&
1574                                  fake_timeout.tv_nsec > timeout->tv_nsec)) {
1575                                 /* FIXME: Real timeout is less than
1576                                  * 100ms time, but is it really worth
1577                                  * calculating to the exact ms?
1578                                  */
1579                                 _wapi_handle_spin (100);
1580
1581                                 if (WAPI_SHARED_HANDLE_DATA(handle).signalled == TRUE) {
1582                                         return (0);
1583                                 } else {
1584                                         return (ETIMEDOUT);
1585                                 }
1586                         }
1587                 }
1588                 _wapi_handle_spin (100);
1589                 return (0);
1590                 
1591         } else {
1592                 guint32 idx = GPOINTER_TO_UINT(handle);
1593                 int res;
1594                 pthread_cond_t *cond;
1595                 mono_mutex_t *mutex;
1596
1597                 if (alertable && !wapi_thread_set_wait_handle (handle))
1598                         return 0;
1599
1600                 cond = &_WAPI_PRIVATE_HANDLES (idx).signal_cond;
1601                 mutex = &_WAPI_PRIVATE_HANDLES (idx).signal_mutex;
1602
1603                 if (poll) {
1604                         /* This is needed when waiting for process handles */
1605                         res = timedwait_signal_poll_cond (cond, mutex, timeout, alertable);
1606                 } else {
1607                         if (timeout)
1608                                 res = mono_cond_timedwait (cond, mutex, timeout);
1609                         else
1610                                 res = mono_cond_wait (cond, mutex);
1611                 }
1612
1613                 if (alertable)
1614                         wapi_thread_clear_wait_handle (handle);
1615
1616                 return res;
1617         }
1618 }
1619
1620 gboolean _wapi_handle_get_or_set_share (dev_t device, ino_t inode,
1621                                         guint32 new_sharemode,
1622                                         guint32 new_access,
1623                                         guint32 *old_sharemode,
1624                                         guint32 *old_access,
1625                                         struct _WapiFileShare **share_info)
1626 {
1627         struct _WapiFileShare *file_share;
1628         guint32 now = (guint32)(time(NULL) & 0xFFFFFFFF);
1629         int thr_ret, i, first_unused = -1;
1630         gboolean exists = FALSE;
1631
1632         /* Prevents entries from expiring under us as we search
1633          */
1634         thr_ret = _wapi_handle_lock_shared_handles ();
1635         g_assert (thr_ret == 0);
1636         
1637         /* Prevent new entries racing with us */
1638         thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
1639         g_assert (thr_ret == 0);
1640         
1641         /* If a linear scan gets too slow we'll have to fit a hash
1642          * table onto the shared mem backing store
1643          */
1644         *share_info = NULL;
1645         for (i = 0; i <= _wapi_fileshare_layout->hwm; i++) {
1646                 file_share = &_wapi_fileshare_layout->share_info[i];
1647
1648                 /* Make a note of an unused slot, in case we need to
1649                  * store share info
1650                  */
1651                 if (first_unused == -1 && file_share->handle_refs == 0) {
1652                         first_unused = i;
1653                         continue;
1654                 }
1655                 
1656                 if (file_share->handle_refs == 0) {
1657                         continue;
1658                 }
1659                 
1660                 if (file_share->device == device &&
1661                     file_share->inode == inode) {
1662                         *old_sharemode = file_share->sharemode;
1663                         *old_access = file_share->access;
1664                         *share_info = file_share;
1665                         
1666                         /* Increment the reference count while we
1667                          * still have sole access to the shared area.
1668                          * This makes the increment atomic wrt
1669                          * collections
1670                          */
1671                         InterlockedIncrement ((gint32 *)&file_share->handle_refs);
1672                         
1673                         exists = TRUE;
1674                         break;
1675                 }
1676         }
1677         
1678         if (!exists) {
1679                 if (i == _WAPI_FILESHARE_SIZE && first_unused == -1) {
1680                         /* No more space */
1681                 } else {
1682                         if (first_unused == -1) {
1683                                 file_share = &_wapi_fileshare_layout->share_info[++i];
1684                                 _wapi_fileshare_layout->hwm = i;
1685                         } else {
1686                                 file_share = &_wapi_fileshare_layout->share_info[first_unused];
1687                         }
1688                         
1689                         file_share->device = device;
1690                         file_share->inode = inode;
1691                         file_share->opened_by_pid = _wapi_getpid ();
1692                         file_share->sharemode = new_sharemode;
1693                         file_share->access = new_access;
1694                         file_share->handle_refs = 1;
1695                         *share_info = file_share;
1696                 }
1697         }
1698
1699         if (*share_info != NULL) {
1700                 InterlockedExchange ((gint32 *)&(*share_info)->timestamp, now);
1701         }
1702         
1703         thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
1704
1705         _wapi_handle_unlock_shared_handles ();
1706
1707         return(exists);
1708 }
1709
1710 /* If we don't have the info in /proc, check if the process that
1711  * opened this share info is still there (it's not a perfect method,
1712  * due to pid reuse)
1713  */
1714 static void _wapi_handle_check_share_by_pid (struct _WapiFileShare *share_info)
1715 {
1716         if (kill (share_info->opened_by_pid, 0) == -1 &&
1717             (errno == ESRCH ||
1718              errno == EPERM)) {
1719                 /* It's gone completely (or there's a new process
1720                  * owned by someone else) so mark this share info as
1721                  * dead
1722                  */
1723 #ifdef DEBUG
1724                 g_message ("%s: Didn't find it, destroying entry", __func__);
1725 #endif
1726
1727                 memset (share_info, '\0', sizeof(struct _WapiFileShare));
1728         }
1729 }
1730
1731 #ifdef __linux__
1732 /* Scan /proc/<pids>/fd/ for open file descriptors to the file in
1733  * question.  If there are none, reset the share info.
1734  *
1735  * This implementation is Linux-specific; legacy systems will have to
1736  * implement their own ways of finding out if a particular file is
1737  * open by a process.
1738  */
1739 void _wapi_handle_check_share (struct _WapiFileShare *share_info, int fd)
1740 {
1741         gboolean found = FALSE, proc_fds = FALSE;
1742         pid_t self = _wapi_getpid ();
1743         int pid;
1744         int thr_ret, i;
1745         
1746         /* Prevents entries from expiring under us if we remove this
1747          * one
1748          */
1749         thr_ret = _wapi_handle_lock_shared_handles ();
1750         g_assert (thr_ret == 0);
1751         
1752         /* Prevent new entries racing with us */
1753         thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
1754         g_assert (thr_ret == 0);
1755         
1756         /* If there is no /proc, there's nothing more we can do here */
1757         if (access ("/proc", F_OK) == -1) {
1758                 _wapi_handle_check_share_by_pid (share_info);
1759                 goto done;
1760         }
1761
1762         /* If there's another handle that thinks it owns this fd, then even
1763          * if the fd has been closed behind our back consider it still owned.
1764          * See bugs 75764 and 75891
1765          */
1766         for (i = 0; i < _wapi_fd_reserve; i++) {
1767                 if (_wapi_private_handles [SLOT_INDEX (i)]) {
1768                         struct _WapiHandleUnshared *handle = &_WAPI_PRIVATE_HANDLES(i);
1769
1770                         if (i != fd &&
1771                                 handle->type == WAPI_HANDLE_FILE) {
1772                                 struct _WapiHandle_file *file_handle = &handle->u.file;
1773
1774                                 if (file_handle->share_info == share_info) {
1775 #ifdef DEBUG
1776                                         g_message ("%s: handle 0x%x has this file open!",
1777                                                            __func__, i);
1778 #endif
1779
1780                                         goto done;
1781                                 }
1782                         }
1783                 }
1784         }
1785
1786         for (i = 0; i < _WAPI_HANDLE_INITIAL_COUNT; i++) {
1787                 struct _WapiHandleShared *shared;
1788                 struct _WapiHandle_process *process_handle;
1789
1790                 shared = &_wapi_shared_layout->handles[i];
1791                 
1792                 if (shared->type == WAPI_HANDLE_PROCESS) {
1793                         DIR *fd_dir;
1794                         struct dirent *fd_entry;
1795                         char subdir[_POSIX_PATH_MAX];
1796
1797                         process_handle = &shared->u.process;
1798                         pid = process_handle->id;
1799                 
1800                         /* Look in /proc/<pid>/fd/ but ignore
1801                          * /proc/<our pid>/fd/<fd>, as we have the
1802                          * file open too
1803                          */
1804                         g_snprintf (subdir, _POSIX_PATH_MAX, "/proc/%d/fd",
1805                                     pid);
1806                         
1807                         fd_dir = opendir (subdir);
1808                         if (fd_dir == NULL) {
1809                                 continue;
1810                         }
1811
1812 #ifdef DEBUG
1813                         g_message ("%s: Looking in %s", __func__, subdir);
1814 #endif
1815                         
1816                         proc_fds = TRUE;
1817                         
1818                         while ((fd_entry = readdir (fd_dir)) != NULL) {
1819                                 char path[_POSIX_PATH_MAX];
1820                                 struct stat link_stat;
1821                                 
1822                                 if (!strcmp (fd_entry->d_name, ".") ||
1823                                     !strcmp (fd_entry->d_name, "..") ||
1824                                     (pid == self &&
1825                                      fd == atoi (fd_entry->d_name))) {
1826                                         continue;
1827                                 }
1828
1829                                 g_snprintf (path, _POSIX_PATH_MAX,
1830                                             "/proc/%d/fd/%s", pid,
1831                                             fd_entry->d_name);
1832                                 
1833                                 stat (path, &link_stat);
1834                                 if (link_stat.st_dev == share_info->device &&
1835                                     link_stat.st_ino == share_info->inode) {
1836 #ifdef DEBUG
1837                                         g_message ("%s:  Found it at %s",
1838                                                    __func__, path);
1839 #endif
1840
1841                                         found = TRUE;
1842                                 }
1843                         }
1844                         
1845                         closedir (fd_dir);
1846                 }
1847         }
1848
1849         if (proc_fds == FALSE) {
1850                 _wapi_handle_check_share_by_pid (share_info);
1851         } else if (found == FALSE) {
1852                 /* Blank out this entry, as it is stale */
1853 #ifdef DEBUG
1854                 g_message ("%s: Didn't find it, destroying entry", __func__);
1855 #endif
1856
1857                 memset (share_info, '\0', sizeof(struct _WapiFileShare));
1858         }
1859
1860 done:
1861         thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
1862
1863         _wapi_handle_unlock_shared_handles ();
1864 }
1865 #else
1866 //
1867 // Other implementations (non-Linux)
1868 //
1869 void _wapi_handle_check_share (struct _WapiFileShare *share_info, int fd)
1870 {
1871         int thr_ret;
1872         
1873         /* Prevents entries from expiring under us if we remove this
1874          * one */
1875         thr_ret = _wapi_handle_lock_shared_handles ();
1876         g_assert (thr_ret == 0);
1877         
1878         /* Prevent new entries racing with us */
1879         thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
1880         g_assert (thr_ret == 0);
1881         
1882         _wapi_handle_check_share_by_pid (share_info);
1883
1884         thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
1885         _wapi_handle_unlock_shared_handles ();
1886 }
1887 #endif
1888
1889 void _wapi_handle_dump (void)
1890 {
1891         struct _WapiHandleUnshared *handle_data;
1892         guint32 i, k;
1893         int thr_ret;
1894         
1895         pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
1896                               (void *)&scan_mutex);
1897         thr_ret = mono_mutex_lock (&scan_mutex);
1898         g_assert (thr_ret == 0);
1899         
1900         for(i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) {
1901                 if (_wapi_private_handles [i]) {
1902                         for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
1903                                 handle_data = &_wapi_private_handles [i][k];
1904
1905                                 if (handle_data->type == WAPI_HANDLE_UNUSED) {
1906                                         continue;
1907                                 }
1908                 
1909                                 g_print ("%3x [%7s] %s %d ",
1910                                                  i * _WAPI_HANDLE_INITIAL_COUNT + k,
1911                                                  _wapi_handle_typename[handle_data->type],
1912                                                  handle_data->signalled?"Sg":"Un",
1913                                                  handle_data->ref);
1914                                 handle_details[handle_data->type](&handle_data->u);
1915                                 g_print ("\n");
1916                         }
1917                 }
1918         }
1919
1920         thr_ret = mono_mutex_unlock (&scan_mutex);
1921         g_assert (thr_ret == 0);
1922         pthread_cleanup_pop (0);
1923 }
1924
1925 static void _wapi_shared_details (gpointer handle_info)
1926 {
1927         struct _WapiHandle_shared_ref *shared = (struct _WapiHandle_shared_ref *)handle_info;
1928         
1929         g_print ("offset: 0x%x", shared->offset);
1930 }
1931
1932 void _wapi_handle_update_refs (void)
1933 {
1934         guint32 i, k;
1935         int thr_ret;
1936         guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
1937         
1938         thr_ret = _wapi_handle_lock_shared_handles ();
1939         g_assert (thr_ret == 0);
1940
1941         /* Prevent file share entries racing with us */
1942         thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
1943         g_assert(thr_ret == 0);
1944
1945         pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
1946                               (void *)&scan_mutex);
1947         thr_ret = mono_mutex_lock (&scan_mutex);
1948         
1949         for(i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) {
1950                 if (_wapi_private_handles [i]) {
1951                         for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
1952                                 struct _WapiHandleUnshared *handle = &_wapi_private_handles [i][k];
1953
1954                                 if (_WAPI_SHARED_HANDLE(handle->type)) {
1955                                         struct _WapiHandleShared *shared_data;
1956                                 
1957 #ifdef DEBUG
1958                                         g_message ("%s: (%d) handle 0x%x is SHARED (%s)", __func__, _wapi_getpid (), i * _WAPI_HANDLE_INITIAL_COUNT + k, _wapi_handle_typename[handle->type]);
1959 #endif
1960
1961                                         shared_data = &_wapi_shared_layout->handles[handle->u.shared.offset];
1962
1963 #ifdef DEBUG
1964                                         g_message ("%s: (%d) Updating timestamp of handle 0x%x", __func__, _wapi_getpid (), handle->u.shared.offset);
1965 #endif
1966
1967                                         InterlockedExchange ((gint32 *)&shared_data->timestamp, now);
1968                                 } else if (handle->type == WAPI_HANDLE_FILE) {
1969                                         struct _WapiHandle_file *file_handle = &handle->u.file;
1970                                 
1971 #ifdef DEBUG
1972                                         g_message ("%s: (%d) handle 0x%x is FILE", __func__, _wapi_getpid (), i * _WAPI_HANDLE_INITIAL_COUNT + k);
1973 #endif
1974                                 
1975                                         g_assert (file_handle->share_info != NULL);
1976
1977 #ifdef DEBUG
1978                                         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));
1979 #endif
1980
1981                                         InterlockedExchange ((gint32 *)&file_handle->share_info->timestamp, now);
1982                                 }
1983                         }
1984                 }
1985         }
1986
1987         thr_ret = mono_mutex_unlock (&scan_mutex);
1988         g_assert (thr_ret == 0);
1989         pthread_cleanup_pop (0);
1990         
1991         thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
1992
1993         _wapi_handle_unlock_shared_handles ();
1994 }
1995