2005-05-13 Zoltan Varga <vargaz@freemail.hu>
[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 Ximian, 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 #include <sys/socket.h>
18 #include <sys/un.h>
19 #include <sys/mman.h>
20 #include <dirent.h>
21 #include <sys/stat.h>
22
23 #include <mono/os/gc_wrapper.h>
24
25 #include <mono/io-layer/wapi.h>
26 #include <mono/io-layer/wapi-private.h>
27 #include <mono/io-layer/handles-private.h>
28 #include <mono/io-layer/mono-mutex.h>
29 #include <mono/io-layer/misc-private.h>
30 #include <mono/io-layer/shared.h>
31 #include <mono/io-layer/collection.h>
32
33 #undef DEBUG
34 #undef DEBUG_REFS
35
36 static void (*_wapi_handle_ops_get_close_func (WapiHandleType type))(gpointer, gpointer);
37
38 static WapiHandleCapability handle_caps[WAPI_HANDLE_COUNT]={0};
39 static struct _WapiHandleOps *handle_ops[WAPI_HANDLE_COUNT]={
40         NULL,
41         &_wapi_file_ops,
42         &_wapi_console_ops,
43         &_wapi_thread_ops,
44         &_wapi_sem_ops,
45         &_wapi_mutex_ops,
46         &_wapi_event_ops,
47         &_wapi_socket_ops,
48         &_wapi_find_ops,
49         &_wapi_process_ops,
50         &_wapi_pipe_ops,
51         &_wapi_namedmutex_ops,
52 };
53
54 static void _wapi_shared_details (gpointer handle_info);
55
56 static void (*handle_details[WAPI_HANDLE_COUNT])(gpointer) = {
57         NULL,
58         _wapi_file_details,
59         _wapi_console_details,
60         _wapi_shared_details,   /* thread */
61         _wapi_sem_details,
62         _wapi_mutex_details,
63         _wapi_event_details,
64         NULL,                   /* Nothing useful to see in a socket handle */
65         NULL,                   /* Nothing useful to see in a find handle */
66         _wapi_shared_details,   /* process */
67         _wapi_pipe_details,
68         _wapi_shared_details,   /* namedmutex */
69 };
70
71 const char *_wapi_handle_typename[] = {
72         "Unused",
73         "File",
74         "Console",
75         "Thread",
76         "Sem",
77         "Mutex",
78         "Event",
79         "Socket",
80         "Find",
81         "Process",
82         "Pipe",
83         "N.Mutex",
84         "Error!!"
85 };
86
87 /*
88  * We can hold _WAPI_PRIVATE_MAX_SLOTS * _WAPI_HANDLE_INITIAL_COUNT handles.
89  * If 4M handles are not enough... Oh, well... we will crash.
90  */
91 #define SLOT_INDEX(x)   (x / _WAPI_HANDLE_INITIAL_COUNT)
92 #define SLOT_OFFSET(x)  (x % _WAPI_HANDLE_INITIAL_COUNT)
93
94 struct _WapiHandleUnshared *_wapi_private_handles [_WAPI_PRIVATE_MAX_SLOTS];
95 static guint32 _wapi_private_handle_count = 0;
96
97 struct _WapiHandleSharedLayout *_wapi_shared_layout = NULL;
98 struct _WapiFileShareLayout *_wapi_fileshare_layout = NULL;
99
100 guint32 _wapi_fd_reserve;
101
102 mono_mutex_t _wapi_global_signal_mutex;
103 pthread_cond_t _wapi_global_signal_cond;
104
105 int _wapi_sem_id;
106
107 static mono_mutex_t scan_mutex = MONO_MUTEX_INITIALIZER;
108
109 static mono_once_t shared_init_once = MONO_ONCE_INIT;
110 static void shared_init (void)
111 {
112         int thr_ret;
113         int idx = 0;
114         
115         _wapi_fd_reserve = getdtablesize();
116
117         do {
118                 _wapi_private_handles [idx++] = g_new0 (struct _WapiHandleUnshared,
119                                                         _WAPI_HANDLE_INITIAL_COUNT);
120
121                 _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
122         } while(_wapi_fd_reserve > _wapi_private_handle_count);
123         
124         _wapi_shared_layout = _wapi_shm_attach (WAPI_SHM_DATA);
125         g_assert (_wapi_shared_layout != NULL);
126
127         _wapi_shm_semaphores_init ();
128         
129         _wapi_fileshare_layout = _wapi_shm_attach (WAPI_SHM_FILESHARE);
130         g_assert (_wapi_fileshare_layout != NULL);
131         
132         _wapi_collection_init ();
133         
134         thr_ret = pthread_cond_init(&_wapi_global_signal_cond, NULL);
135         g_assert (thr_ret == 0);
136         
137         thr_ret = mono_mutex_init(&_wapi_global_signal_mutex, NULL);
138         g_assert (thr_ret == 0);
139 }
140
141 static void _wapi_handle_init_shared_metadata (struct _WapiHandleSharedMetadata *meta)
142 {
143         meta->timestamp = (guint32)(time (NULL) & 0xFFFFFFFF);
144         meta->signalled = FALSE;
145 }
146
147 static void _wapi_handle_init_shared (struct _WapiHandleShared *handle,
148                                       WapiHandleType type,
149                                       gpointer handle_specific)
150 {
151         handle->type = type;
152         handle->stale = FALSE;
153         
154         if (handle_specific != NULL) {
155                 memcpy (&handle->u, handle_specific, sizeof (handle->u));
156         }
157 }
158
159 static void _wapi_handle_init (struct _WapiHandleUnshared *handle,
160                                WapiHandleType type, gpointer handle_specific)
161 {
162         int thr_ret;
163         
164         handle->type = type;
165         handle->signalled = FALSE;
166         handle->ref = 1;
167         
168         if (!_WAPI_SHARED_HANDLE(type)) {
169                 thr_ret = pthread_cond_init (&handle->signal_cond, NULL);
170                 g_assert (thr_ret == 0);
171                                 
172                 thr_ret = mono_mutex_init (&handle->signal_mutex, NULL);
173                 g_assert (thr_ret == 0);
174
175                 if (handle_specific != NULL) {
176                         memcpy (&handle->u, handle_specific,
177                                 sizeof (handle->u));
178                 }
179         }
180 }
181
182 static guint32 _wapi_handle_new_shared_offset (guint32 offset)
183 {
184         guint32 i;
185         static guint32 last = 1;
186         
187 again:
188         /* FIXME: expandable array */
189         /* leave a few slots at the end so that there's always space
190          * to move a handle.  (We leave the space in the offset table
191          * too, so we don't have to keep track of inter-segment
192          * offsets.)
193          */
194         for(i = last; i <_WAPI_HANDLE_INITIAL_COUNT - _WAPI_HEADROOM; i++) {
195                 struct _WapiHandleSharedMetadata *meta = &_wapi_shared_layout->metadata[i];
196                 
197                 if(meta->offset == 0) {
198                         if (InterlockedCompareExchange (&meta->offset, offset,
199                                                         0) == 0) {
200                                 last = i + 1;
201                         
202                                 _wapi_handle_init_shared_metadata (meta);
203                                 return(i);
204                         } else {
205                                 /* Someone else beat us to it, just
206                                  * continue looking
207                                  */
208                         }
209                 }
210         }
211
212         if(last > 1) {
213                 /* Try again from the beginning */
214                 last = 1;
215                 goto again;
216         }
217
218         /* Will need to expand the array.  The caller will sort it out */
219
220         return(0);
221 }
222
223 static guint32 _wapi_handle_new_shared (WapiHandleType type,
224                                         gpointer handle_specific)
225 {
226         guint32 offset;
227         static guint32 last = 1;
228         
229         /* The shared memory holds an offset to the real data, so we
230          * can update the handle RCU-style without taking a lock.
231          * This function just allocates the next available data slot,
232          * use _wapi_handle_new_shared_offset to get the offset entry.
233          */
234
235         /* Leave the first slot empty as a guard */
236 again:
237         /* FIXME: expandable array */
238         /* Leave a few slots at the end so that there's always space
239          * to move a handle
240          */
241         for(offset = last; offset <_WAPI_HANDLE_INITIAL_COUNT - _WAPI_HEADROOM;
242             offset++) {
243                 struct _WapiHandleShared *handle = &_wapi_shared_layout->handles[offset];
244                 
245                 if(handle->type == WAPI_HANDLE_UNUSED) {
246                         if (InterlockedCompareExchange ((gint32 *)&handle->type, type, WAPI_HANDLE_UNUSED) == WAPI_HANDLE_UNUSED) {
247                                 last = offset + 1;
248                         
249                                 _wapi_handle_init_shared (handle, type,
250                                                           handle_specific);
251                                 return(offset);
252                         } else {
253                                 /* Someone else beat us to it, just
254                                  * continue looking
255                                  */
256                         }
257                 }
258         }
259
260         if(last > 1) {
261                 /* Try again from the beginning */
262                 last = 1;
263                 goto again;
264         }
265
266         /* Will need to expand the array.  The caller will sort it out */
267
268         return(0);
269 }
270
271 /*
272  * _wapi_handle_new_internal:
273  * @type: Init handle to this type
274  *
275  * Search for a free handle and initialize it. Return the handle on
276  * success and 0 on failure.  This is only called from
277  * _wapi_handle_new, and scan_mutex must be held.
278  */
279 static guint32 _wapi_handle_new_internal (WapiHandleType type,
280                                           gpointer handle_specific)
281 {
282         guint32 i, k, count;
283         static guint32 last = 0;
284         gboolean retry = FALSE;
285         
286         /* A linear scan should be fast enough.  Start from the last
287          * allocation, assuming that handles are allocated more often
288          * than they're freed. Leave the space reserved for file
289          * descriptors
290          */
291         
292         if (last < _wapi_fd_reserve) {
293                 last = _wapi_fd_reserve;
294         } else {
295                 retry = TRUE;
296         }
297
298 again:
299         count = last;
300         for(i = SLOT_INDEX (count); _wapi_private_handles [i] != NULL; i++) {
301                 for (k = SLOT_OFFSET (count); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
302                         struct _WapiHandleUnshared *handle = &_wapi_private_handles [i][k];
303
304                         if(handle->type == WAPI_HANDLE_UNUSED) {
305                                 last = count + 1;
306                         
307                                 _wapi_handle_init (handle, type, handle_specific);
308                                 return (count);
309                         }
310                         count++;
311                 }
312         }
313
314         if(retry && last > _wapi_fd_reserve) {
315                 /* Try again from the beginning */
316                 last = _wapi_fd_reserve;
317                 goto again;
318         }
319
320         /* Will need to expand the array.  The caller will sort it out */
321
322         return(0);
323 }
324
325 gpointer _wapi_handle_new (WapiHandleType type, gpointer handle_specific)
326 {
327         guint32 handle_idx = 0;
328         gpointer handle;
329         int thr_ret;
330         
331         mono_once (&shared_init_once, shared_init);
332         
333 #ifdef DEBUG
334         g_message ("%s: Creating new handle of type %s", __func__,
335                    _wapi_handle_typename[type]);
336 #endif
337
338         g_assert(!_WAPI_FD_HANDLE(type));
339         
340         pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
341                               (void *)&scan_mutex);
342         thr_ret = mono_mutex_lock (&scan_mutex);
343         g_assert (thr_ret == 0);
344                 
345         while ((handle_idx = _wapi_handle_new_internal (type, handle_specific)) == 0) {
346                 /* Try and expand the array, and have another go */
347                 int idx = SLOT_INDEX (_wapi_private_handle_count);
348                 _wapi_private_handles [idx] = g_new0 (struct _WapiHandleUnshared,
349                                                 _WAPI_HANDLE_INITIAL_COUNT);
350
351                 _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
352         }
353                 
354         thr_ret = mono_mutex_unlock (&scan_mutex);
355         g_assert (thr_ret == 0);
356         pthread_cleanup_pop (0);
357                 
358         /* Make sure we left the space for fd mappings */
359         g_assert (handle_idx >= _wapi_fd_reserve);
360         
361         handle = GUINT_TO_POINTER (handle_idx);
362
363 #ifdef DEBUG
364         g_message ("%s: Allocated new handle %p", __func__, handle);
365 #endif
366         
367         if (_WAPI_SHARED_HANDLE(type)) {
368                 /* Add the shared section too */
369                 guint32 offset, ref;
370                 
371                 offset = _wapi_handle_new_shared (type, handle_specific);
372                 if (offset == 0) {
373                         _wapi_handle_collect ();
374                         offset = _wapi_handle_new_shared (type,
375                                                           handle_specific);
376                         if (offset == 0) {
377                                 /* FIXME: grow the arrays */
378                                 return (_WAPI_HANDLE_INVALID);
379                         }
380                 }
381                 
382                 ref = _wapi_handle_new_shared_offset (offset);
383                 if (ref == 0) {
384                         _wapi_handle_collect ();
385                         ref = _wapi_handle_new_shared_offset (offset);
386
387                         if (ref == 0) {
388                                 /* FIXME: grow the arrays */
389                                 return (_WAPI_HANDLE_INVALID);
390                         }
391                 }
392                 
393                 _WAPI_PRIVATE_HANDLES(handle_idx).u.shared.offset = ref;
394 #ifdef DEBUG
395                 g_message ("%s: New shared handle at offset 0x%x", __func__,
396                            ref);
397 #endif
398         }
399         
400         return(handle);
401 }
402
403 gpointer _wapi_handle_new_from_offset (WapiHandleType type, guint32 offset)
404 {
405         guint32 handle_idx = 0;
406         gpointer handle;
407         int thr_ret, i, k;
408         
409         mono_once (&shared_init_once, shared_init);
410         
411 #ifdef DEBUG
412         g_message ("%s: Creating new handle of type %s to offset %d", __func__,
413                    _wapi_handle_typename[type], offset);
414 #endif
415
416         g_assert(!_WAPI_FD_HANDLE(type));
417         g_assert(_WAPI_SHARED_HANDLE(type));
418         g_assert(offset != 0);
419                 
420         for (i = SLOT_INDEX (0); _wapi_private_handles [i] != NULL; i++) {
421                 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
422                         struct _WapiHandleUnshared *handle_data = &_wapi_private_handles [i][k];
423                 
424                         if (handle_data->type == type &&
425                             handle_data->u.shared.offset == offset) {
426                                 handle = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
427                                 _wapi_handle_ref (handle);
428
429 #ifdef DEBUG
430                                 g_message ("%s: Returning old handle %p referencing 0x%x", __func__, handle, offset);
431 #endif
432                                 return (handle);
433                         }
434                 }
435         }
436
437         pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
438                               (void *)&scan_mutex);
439         thr_ret = mono_mutex_lock (&scan_mutex);
440         g_assert (thr_ret == 0);
441         
442         while ((handle_idx = _wapi_handle_new_internal (type, NULL)) == 0) {
443                 /* Try and expand the array, and have another go */
444                 int idx = SLOT_INDEX (_wapi_private_handle_count);
445                 _wapi_private_handles [idx] = g_new0 (struct _WapiHandleUnshared,
446                                                 _WAPI_HANDLE_INITIAL_COUNT);
447
448                 _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
449         }
450                 
451         thr_ret = mono_mutex_unlock (&scan_mutex);
452         g_assert (thr_ret == 0);
453         pthread_cleanup_pop (0);
454                 
455         /* Make sure we left the space for fd mappings */
456         g_assert (handle_idx >= _wapi_fd_reserve);
457         
458         handle = GUINT_TO_POINTER (handle_idx);
459                 
460         _WAPI_PRIVATE_HANDLES(handle_idx).u.shared.offset = offset;
461
462 #ifdef DEBUG
463         g_message ("%s: Allocated new handle %p referencing 0x%x", __func__,
464                    handle, offset);
465 #endif
466
467         return(handle);
468 }
469
470 gpointer _wapi_handle_new_fd (WapiHandleType type, int fd,
471                               gpointer handle_specific)
472 {
473         struct _WapiHandleUnshared *handle;
474         
475         mono_once (&shared_init_once, shared_init);
476         
477 #ifdef DEBUG
478         g_message ("%s: Creating new handle of type %s", __func__,
479                    _wapi_handle_typename[type]);
480 #endif
481         
482         g_assert(_WAPI_FD_HANDLE(type));
483         g_assert(!_WAPI_SHARED_HANDLE(type));
484         
485         if (fd >= _wapi_fd_reserve) {
486 #ifdef DEBUG
487                 g_message ("%s: fd %d is too big", __func__, fd);
488 #endif
489
490                 return(GUINT_TO_POINTER (_WAPI_HANDLE_INVALID));
491         }
492
493         handle = &_WAPI_PRIVATE_HANDLES(fd);
494         
495         if (handle->type != WAPI_HANDLE_UNUSED) {
496 #ifdef DEBUG
497                 g_message ("%s: fd %d is already in use!", __func__, fd);
498 #endif
499                 /* FIXME: clean up this handle?  We can't do anything
500                  * with the fd, cos thats the new one
501                  */
502         }
503
504 #ifdef DEBUG
505         g_message ("%s: Assigning new fd handle %d", __func__, fd);
506 #endif
507
508         _wapi_handle_init (handle, type, handle_specific);
509
510         return(GUINT_TO_POINTER(fd));
511 }
512
513 gboolean _wapi_lookup_handle (gpointer handle, WapiHandleType type,
514                               gpointer *handle_specific)
515 {
516         struct _WapiHandleUnshared *handle_data;
517         guint32 handle_idx = GPOINTER_TO_UINT(handle);
518
519         handle_data = &_WAPI_PRIVATE_HANDLES(handle_idx);
520         
521         if (handle_data->type != type) {
522                 return(FALSE);
523         }
524
525         if (handle_specific == NULL) {
526                 return(FALSE);
527         }
528         
529         if (_WAPI_SHARED_HANDLE(type)) {
530                 struct _WapiHandle_shared_ref *ref;
531                 struct _WapiHandleShared *shared_handle_data;
532                 struct _WapiHandleSharedMetadata *shared_meta;
533                 guint32 offset;
534                         
535                 /* Unsafe, because we don't want the handle to vanish
536                  * while we're checking it
537                  */
538                 _WAPI_HANDLE_COLLECTION_UNSAFE;
539                 
540                 do {
541                         ref = &handle_data->u.shared;
542                         shared_meta = &_wapi_shared_layout->metadata[ref->offset];
543                         offset = shared_meta->offset;
544                         shared_handle_data = &_wapi_shared_layout->handles[offset];
545                 
546                         g_assert(shared_handle_data->type == type);
547
548                         *handle_specific = &shared_handle_data->u;
549                 } while (offset != shared_meta->offset);
550
551                 _WAPI_HANDLE_COLLECTION_SAFE;
552         } else {
553                 *handle_specific = &handle_data->u;
554         }
555         
556         return(TRUE);
557 }
558
559 gboolean _wapi_copy_handle (gpointer handle, WapiHandleType type,
560                             struct _WapiHandleShared *handle_specific)
561 {
562         struct _WapiHandleUnshared *handle_data;
563         guint32 handle_idx = GPOINTER_TO_UINT(handle);
564         struct _WapiHandle_shared_ref *ref;
565         struct _WapiHandleShared *shared_handle_data;
566         struct _WapiHandleSharedMetadata *shared_meta;
567         guint32 offset;
568         
569         g_assert(_WAPI_SHARED_HANDLE(type));
570
571 #ifdef DEBUG
572         g_message ("%s: copying handle %p type %s", __func__, handle,
573                    _wapi_handle_typename[type]);
574 #endif
575
576         handle_data = &_WAPI_PRIVATE_HANDLES(handle_idx);
577         
578         if(handle_data->type != type) {
579 #ifdef DEBUG
580                 g_message ("%s: incorrect type, %p has type %s", __func__,
581                            handle, _wapi_handle_typename[handle_data->type]);
582 #endif
583
584                 return(FALSE);
585         }
586
587         if(handle_specific == NULL) {
588 #ifdef DEBUG
589                 g_message ("%s: Nowhere to store data", __func__);
590 #endif
591
592                 return(FALSE);
593         }
594         
595         do {
596                 ref = &handle_data->u.shared;
597                 shared_meta = &_wapi_shared_layout->metadata[ref->offset];
598                 offset = shared_meta->offset;
599                 shared_handle_data = &_wapi_shared_layout->handles[offset];
600                 
601                 g_assert(shared_handle_data->type == type);
602                 
603                 memcpy(handle_specific, shared_handle_data,
604                        sizeof(struct _WapiHandleShared));
605         } while (offset != shared_meta->offset);
606         
607 #ifdef DEBUG
608         g_message ("%s: OK", __func__);
609 #endif
610
611         return(TRUE);
612 }
613
614 gboolean _wapi_replace_handle (gpointer handle, WapiHandleType type,
615                                struct _WapiHandleShared *handle_specific)
616 {
617         struct _WapiHandleShared *shared_handle_data;
618         struct _WapiHandleSharedMetadata *shared_meta;
619         guint32 handle_idx = GPOINTER_TO_UINT(handle);
620         guint32 old_off, new_off, ref;
621         
622 #ifdef DEBUG
623         g_message ("%s: Replacing handle %p of type %s", __func__, handle,
624                    _wapi_handle_typename[type]);
625 #endif
626
627         g_assert(_WAPI_SHARED_HANDLE(type));
628         g_assert(_WAPI_PRIVATE_HANDLES(handle_idx).type == type);
629         
630         ref = _WAPI_PRIVATE_HANDLES(handle_idx).u.shared.offset;
631         shared_meta = &_wapi_shared_layout->metadata[ref];
632         
633         do {
634                 old_off = shared_meta->offset;
635                 new_off = _wapi_handle_new_shared (type, handle_specific);
636                 if (new_off == 0) {
637                         _wapi_handle_collect ();
638                         new_off = _wapi_handle_new_shared (type, 
639                                                            handle_specific);
640
641                         if (new_off == 0) {
642                                 /* FIXME: grow the arrays */
643                                 return (FALSE);
644                         }
645                 }
646                 
647                 shared_handle_data = &_wapi_shared_layout->handles[new_off];
648
649                 memcpy (shared_handle_data, handle_specific,
650                         sizeof(struct _WapiHandleShared));
651
652                 /* An entry can't become fresh again (its going to be
653                  * collected eventually), so no need for atomic ops
654                  * here.
655                  */
656                 _wapi_shared_layout->handles[old_off].stale = TRUE;
657         } while(InterlockedCompareExchange (&shared_meta->offset, new_off,
658                                             old_off) != old_off);
659
660 #ifdef DEBUG
661         g_message ("%s: handle at 0x%x is now found at 0x%x", __func__, ref,
662                    new_off);
663 #endif
664
665         return (TRUE);
666 }
667
668 void
669 _wapi_handle_foreach (WapiHandleType type,
670                         gboolean (*on_each)(gpointer test, gpointer user),
671                         gpointer user_data)
672 {
673         struct _WapiHandleUnshared *handle_data = NULL;
674         gpointer ret = NULL;
675         guint32 i, k;
676         int thr_ret;
677
678         pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
679                               (void *)&scan_mutex);
680         thr_ret = mono_mutex_lock (&scan_mutex);
681         g_assert (thr_ret == 0);
682
683         for (i = SLOT_INDEX (0); _wapi_private_handles [i] != NULL; i++) {
684                 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
685                         handle_data = &_wapi_private_handles [i][k];
686                 
687                         if (handle_data->type == type) {
688                                 ret = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
689                                 if (on_each (ret, user_data) == TRUE)
690                                         break;
691                         }
692                 }
693         }
694
695         thr_ret = mono_mutex_unlock (&scan_mutex);
696         g_assert (thr_ret == 0);
697         pthread_cleanup_pop (0);
698 }
699
700 /* This might list some shared handles twice if they are already
701  * opened by this process, and the check function returns FALSE the
702  * first time.  Shared handles that are created during the search are
703  * unreffed if the check function returns FALSE, so callers must not
704  * rely on the handle persisting (unless the check function returns
705  * TRUE)
706  */
707 gpointer _wapi_search_handle (WapiHandleType type,
708                               gboolean (*check)(gpointer test, gpointer user),
709                               gpointer user_data,
710                               gpointer *handle_specific)
711 {
712         struct _WapiHandleUnshared *handle_data = NULL;
713         gpointer ret = NULL;
714         guint32 i, k;
715         gboolean found = FALSE;
716
717
718         for (i = SLOT_INDEX (0); !found && _wapi_private_handles [i] != NULL; i++) {
719                 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
720                         handle_data = &_wapi_private_handles [i][k];
721                 
722                         if (handle_data->type == type) {
723                                 ret = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
724                                 if (check (ret, user_data) == TRUE) {
725                                         found = TRUE;
726                                         break;
727                                 }
728                         }
729                 }
730         }
731
732         if (!found) {
733                 /* Not found yet, so search the shared memory too */
734 #ifdef DEBUG
735                 g_message ("%s: Looking at other shared handles...", __func__);
736 #endif
737
738                 for (i = 0; i < _WAPI_HANDLE_INITIAL_COUNT; i++) {
739                         struct _WapiHandleShared *shared;
740                         struct _WapiHandleSharedMetadata *meta;
741                         WapiHandleType shared_type;
742
743                         _WAPI_HANDLE_COLLECTION_UNSAFE;
744
745                         meta = &_wapi_shared_layout->metadata[i];
746                         shared = &_wapi_shared_layout->handles[meta->offset];
747                         shared_type = shared->type;
748                         
749                         _WAPI_HANDLE_COLLECTION_SAFE;
750                         
751                         if (shared_type == type) {
752                                 ret = _wapi_handle_new_from_offset (type, i);
753
754 #ifdef DEBUG
755                                 g_message ("%s: Opened tmp handle %p (type %s) from offset %d", __func__, ret, _wapi_handle_typename[type], meta->offset);
756 #endif
757
758                                 if (check (ret, user_data) == TRUE) {
759                                         found = TRUE;
760                                         handle_data = &_WAPI_PRIVATE_HANDLES(GPOINTER_TO_UINT(ret));
761                                         
762                                         break;
763                                 }
764                                 
765                                 /* This isn't the handle we're looking
766                                  * for, so drop the reference we took
767                                  * in _wapi_handle_new_from_offset ()
768                                  */
769                                 _wapi_handle_unref (ret);
770                         }
771                 }
772         }
773         
774         if (!found) {
775                 goto done;
776         }
777         
778         if(handle_specific != NULL) {
779                 if (_WAPI_SHARED_HANDLE(type)) {
780                         struct _WapiHandle_shared_ref *ref ;
781                         struct _WapiHandleShared *shared_handle_data;
782                         struct _WapiHandleSharedMetadata *shared_meta;
783                         guint32 offset, now;
784                         
785                         /* Unsafe, because we don't want the handle to
786                          * vanish while we're checking it
787                          */
788                         _WAPI_HANDLE_COLLECTION_UNSAFE;
789
790                         do {
791                                 ref = &handle_data->u.shared;
792                                 shared_meta = &_wapi_shared_layout->metadata[ref->offset];
793                                 offset = shared_meta->offset;
794                                 shared_handle_data = &_wapi_shared_layout->handles[offset];
795                         
796                                 g_assert(shared_handle_data->type == type);
797                         
798                                 *handle_specific = &shared_handle_data->u;
799                         } while (offset != shared_meta->offset);
800
801                         /* Make sure this handle doesn't vanish in the
802                          * next collection
803                          */
804                         now = (guint32)(time (NULL) & 0xFFFFFFFF);
805                         InterlockedExchange (&shared_meta->timestamp, now);
806
807                         _WAPI_HANDLE_COLLECTION_SAFE;
808                 } else {
809                         *handle_specific = &handle_data->u;
810                 }
811         }
812
813 done:
814         return(ret);
815 }
816
817 /* Returns the offset of the metadata array, or -1 on error, or 0 for
818  * not found (0 is not a valid offset)
819  */
820 gint32 _wapi_search_handle_namespace (WapiHandleType type,
821                                       gchar *utf8_name)
822 {
823         struct _WapiHandleShared *shared_handle_data;
824         struct _WapiHandleSharedMetadata *shared_meta;
825         guint32 i;
826         gint32 ret = 0;
827         
828         g_assert(_WAPI_SHARED_HANDLE(type));
829         
830 #ifdef DEBUG
831         g_message ("%s: Lookup for handle named [%s] type %s", __func__,
832                    utf8_name, _wapi_handle_typename[type]);
833 #endif
834
835         _WAPI_HANDLE_COLLECTION_UNSAFE;
836         
837         for(i = 1; i < _WAPI_HANDLE_INITIAL_COUNT; i++) {
838                 WapiSharedNamespace *sharedns;
839                 
840                 shared_meta = &_wapi_shared_layout->metadata[i];
841                 shared_handle_data = &_wapi_shared_layout->handles[shared_meta->offset];
842
843                 /* Check mutex, event, semaphore, timer, job and file-mapping
844                  * object names.  So far only mutex is implemented.
845                  */
846                 if (!_WAPI_SHARED_NAMESPACE (shared_handle_data->type)) {
847                         continue;
848                 }
849
850 #ifdef DEBUG
851                 g_message ("%s: found a shared namespace handle at 0x%x (type %s)", __func__, i, _wapi_handle_typename[shared_handle_data->type]);
852 #endif
853
854                 sharedns=(WapiSharedNamespace *)&shared_handle_data->u;
855                         
856 #ifdef DEBUG
857                 g_message ("%s: name is [%s]", __func__, sharedns->name);
858 #endif
859
860                 if (strcmp (sharedns->name, utf8_name) == 0) {
861                         if (shared_handle_data->type != type) {
862                                 /* Its the wrong type, so fail now */
863 #ifdef DEBUG
864                                 g_message ("%s: handle 0x%x matches name but is wrong type: %s", __func__, i, _wapi_handle_typename[shared_handle_data->type]);
865 #endif
866                                 ret = -1;
867                                 goto done;
868                         } else {
869 #ifdef DEBUG
870                                 g_message ("%s: handle 0x%x matches name and type", __func__, i);
871 #endif
872                                 ret = i;
873                                 goto done;
874                         }
875                 }
876         }
877
878 done:
879         _WAPI_HANDLE_COLLECTION_SAFE;
880         
881         return(ret);
882 }
883
884 void _wapi_handle_ref (gpointer handle)
885 {
886         guint32 idx = GPOINTER_TO_UINT(handle);
887         guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
888         struct _WapiHandleUnshared *handle_data = &_WAPI_PRIVATE_HANDLES(idx);
889         
890         InterlockedIncrement (&handle_data->ref);
891
892         /* It's possible for processes to exit before getting around
893          * to updating timestamps in the collection thread, so if a
894          * shared handle is reffed do the timestamp here as well just
895          * to make sure.
896          */
897         if (_WAPI_SHARED_HANDLE(handle_data->type)) {
898                 struct _WapiHandleSharedMetadata *shared_meta = &_wapi_shared_layout->metadata[handle_data->u.shared.offset];
899                 
900                 InterlockedExchange (&shared_meta->timestamp, now);
901         }
902         
903 #ifdef DEBUG_REFS
904         g_message ("%s: handle %p ref now %d", __func__, handle,
905                    _WAPI_PRIVATE_HANDLES(idx).ref);
906 #endif
907 }
908
909 /* The handle must not be locked on entry to this function */
910 void _wapi_handle_unref (gpointer handle)
911 {
912         guint32 idx = GPOINTER_TO_UINT(handle);
913         gboolean destroy = FALSE;
914         int thr_ret;
915
916         /* Possible race condition here if another thread refs the
917          * handle between here and setting the type to UNUSED.  I
918          * could lock a mutex, but I'm not sure that allowing a handle
919          * reference to reach 0 isn't an application bug anyway.
920          */
921         destroy = (InterlockedDecrement (&_WAPI_PRIVATE_HANDLES(idx).ref) ==0);
922         
923 #ifdef DEBUG_REFS
924         g_message ("%s: handle %p ref now %d (destroy %s)", __func__, handle,
925                    _WAPI_PRIVATE_HANDLES(idx).ref, destroy?"TRUE":"FALSE");
926 #endif
927         
928         if(destroy==TRUE) {
929                 /* Need to copy the handle info, reset the slot in the
930                  * array, and _only then_ call the close function to
931                  * avoid race conditions (eg file descriptors being
932                  * closed, and another file being opened getting the
933                  * same fd racing the memset())
934                  */
935                 struct _WapiHandleUnshared handle_data;
936                 WapiHandleType type = _WAPI_PRIVATE_HANDLES(idx).type;
937                 void (*close_func)(gpointer, gpointer) = _wapi_handle_ops_get_close_func (type);
938
939 #ifdef DEBUG
940                 g_message ("%s: Destroying handle %p", __func__, handle);
941 #endif
942                 
943                 memcpy (&handle_data, &_WAPI_PRIVATE_HANDLES(idx),
944                         sizeof (struct _WapiHandleUnshared));
945
946                 memset (&_WAPI_PRIVATE_HANDLES(idx).u, '\0',
947                         sizeof(_WAPI_PRIVATE_HANDLES(idx).u));
948
949                 _WAPI_PRIVATE_HANDLES(idx).type = WAPI_HANDLE_UNUSED;
950                 
951                 if (!_WAPI_SHARED_HANDLE(type)) {
952                         /* Destroy the mutex and cond var.  We hope nobody
953                          * tried to grab them between the handle unlock and
954                          * now, but pthreads doesn't have a
955                          * "unlock_and_destroy" atomic function.
956                          */
957                         thr_ret = mono_mutex_destroy (&_WAPI_PRIVATE_HANDLES(idx).signal_mutex);
958                         g_assert (thr_ret == 0);
959                                 
960                         thr_ret = pthread_cond_destroy (&_WAPI_PRIVATE_HANDLES(idx).signal_cond);
961                         g_assert (thr_ret == 0);
962                 }
963
964                 /* The garbage collector will take care of shared data
965                  * if this is a shared handle
966                  */
967                 
968                 if (close_func != NULL) {
969                         close_func (handle, &handle_data.u);
970                 }
971         }
972 }
973
974 void _wapi_handle_register_capabilities (WapiHandleType type,
975                                          WapiHandleCapability caps)
976 {
977         handle_caps[type] = caps;
978 }
979
980 gboolean _wapi_handle_test_capabilities (gpointer handle,
981                                          WapiHandleCapability caps)
982 {
983         guint32 idx = GPOINTER_TO_UINT(handle);
984         WapiHandleType type;
985
986         type = _WAPI_PRIVATE_HANDLES(idx).type;
987
988 #ifdef DEBUG
989         g_message ("%s: testing 0x%x against 0x%x (%d)", __func__,
990                    handle_caps[type], caps, handle_caps[type] & caps);
991 #endif
992         
993         return((handle_caps[type] & caps) != 0);
994 }
995
996 static void (*_wapi_handle_ops_get_close_func (WapiHandleType type))(gpointer, gpointer)
997 {
998         if (handle_ops[type] != NULL &&
999             handle_ops[type]->close != NULL) {
1000                 return (handle_ops[type]->close);
1001         }
1002
1003         return (NULL);
1004 }
1005
1006 void _wapi_handle_ops_close (gpointer handle, gpointer data)
1007 {
1008         guint32 idx = GPOINTER_TO_UINT(handle);
1009         WapiHandleType type;
1010
1011         type = _WAPI_PRIVATE_HANDLES(idx).type;
1012
1013         if (handle_ops[type] != NULL &&
1014             handle_ops[type]->close != NULL) {
1015                 handle_ops[type]->close (handle, data);
1016         }
1017 }
1018
1019 void _wapi_handle_ops_signal (gpointer handle)
1020 {
1021         guint32 idx = GPOINTER_TO_UINT(handle);
1022         WapiHandleType type;
1023
1024         type = _WAPI_PRIVATE_HANDLES(idx).type;
1025
1026         if (handle_ops[type] != NULL && handle_ops[type]->signal != NULL) {
1027                 handle_ops[type]->signal (handle);
1028         }
1029 }
1030
1031 gboolean _wapi_handle_ops_own (gpointer handle)
1032 {
1033         guint32 idx = GPOINTER_TO_UINT(handle);
1034         WapiHandleType type;
1035         
1036         type = _WAPI_PRIVATE_HANDLES(idx).type;
1037
1038         if (handle_ops[type] != NULL && handle_ops[type]->own_handle != NULL) {
1039                 return(handle_ops[type]->own_handle (handle));
1040         } else {
1041                 return(FALSE);
1042         }
1043 }
1044
1045 gboolean _wapi_handle_ops_isowned (gpointer handle)
1046 {
1047         guint32 idx = GPOINTER_TO_UINT(handle);
1048         WapiHandleType type;
1049
1050         type = _WAPI_PRIVATE_HANDLES(idx).type;
1051
1052         if (handle_ops[type] != NULL && handle_ops[type]->is_owned != NULL) {
1053                 return(handle_ops[type]->is_owned (handle));
1054         } else {
1055                 return(FALSE);
1056         }
1057 }
1058
1059 guint32 _wapi_handle_ops_special_wait (gpointer handle, guint32 timeout)
1060 {
1061         guint32 idx = GPOINTER_TO_UINT(handle);
1062         WapiHandleType type;
1063         
1064         type = _WAPI_PRIVATE_HANDLES(idx).type;
1065         
1066         if (handle_ops[type] != NULL &&
1067             handle_ops[type]->special_wait != NULL) {
1068                 return(handle_ops[type]->special_wait (handle, timeout));
1069         } else {
1070                 return(WAIT_FAILED);
1071         }
1072 }
1073
1074
1075 /**
1076  * CloseHandle:
1077  * @handle: The handle to release
1078  *
1079  * Closes and invalidates @handle, releasing any resources it
1080  * consumes.  When the last handle to a temporary or non-persistent
1081  * object is closed, that object can be deleted.  Closing the same
1082  * handle twice is an error.
1083  *
1084  * Return value: %TRUE on success, %FALSE otherwise.
1085  */
1086 gboolean CloseHandle(gpointer handle)
1087 {
1088         _wapi_handle_unref (handle);
1089         
1090         return(TRUE);
1091 }
1092
1093 gboolean _wapi_handle_count_signalled_handles (guint32 numhandles,
1094                                                gpointer *handles,
1095                                                gboolean waitall,
1096                                                guint32 *retcount,
1097                                                guint32 *lowest)
1098 {
1099         guint32 count, i, iter=0;
1100         gboolean ret;
1101         int thr_ret;
1102         WapiHandleType type;
1103         
1104         /* Lock all the handles, with backoff */
1105 again:
1106         thr_ret = _wapi_handle_lock_shared_handles ();
1107         g_assert (thr_ret == 0);
1108         
1109         for(i=0; i<numhandles; i++) {
1110                 gpointer handle = handles[i];
1111                 guint32 idx = GPOINTER_TO_UINT(handle);
1112
1113 #ifdef DEBUG
1114                 g_message ("%s: attempting to lock %p", __func__, handle);
1115 #endif
1116
1117                 type = _WAPI_PRIVATE_HANDLES(idx).type;
1118
1119                 thr_ret = _wapi_handle_trylock_handle (handle);
1120                 
1121                 if (thr_ret != 0) {
1122                         /* Bummer */
1123                         
1124 #ifdef DEBUG
1125                         g_message ("%s: attempt failed for %p: %s", __func__,
1126                                    handle, strerror (thr_ret));
1127 #endif
1128
1129                         thr_ret = _wapi_handle_unlock_shared_handles ();
1130                         g_assert (thr_ret == 0);
1131                         
1132                         while (i--) {
1133                                 handle = handles[i];
1134                                 idx = GPOINTER_TO_UINT(handle);
1135
1136                                 thr_ret = _wapi_handle_unlock_handle (handle);
1137                                 g_assert (thr_ret == 0);
1138                         }
1139
1140                         /* If iter ever reaches 100 the nanosleep will
1141                          * return EINVAL immediately, but we have a
1142                          * design flaw if that happens.
1143                          */
1144                         iter++;
1145                         if(iter==100) {
1146                                 g_warning ("%s: iteration overflow!",
1147                                            __func__);
1148                                 iter=1;
1149                         }
1150                         
1151 #ifdef DEBUG
1152                         g_message ("%s: Backing off for %d ms", __func__,
1153                                    iter*10);
1154 #endif
1155                         _wapi_handle_spin (10 * iter);
1156                         
1157                         goto again;
1158                 }
1159         }
1160         
1161 #ifdef DEBUG
1162         g_message ("%s: Locked all handles", __func__);
1163 #endif
1164
1165         count=0;
1166         *lowest=numhandles;
1167         
1168         for(i=0; i<numhandles; i++) {
1169                 gpointer handle = handles[i];
1170                 guint32 idx = GPOINTER_TO_UINT(handle);
1171                 
1172                 type = _WAPI_PRIVATE_HANDLES(idx).type;
1173
1174                 _wapi_handle_ref (handle);
1175                 
1176 #ifdef DEBUG
1177                 g_message ("%s: Checking handle %p", __func__, handle);
1178 #endif
1179
1180                 if(((_wapi_handle_test_capabilities (handle, WAPI_HANDLE_CAP_OWN)==TRUE) &&
1181                     (_wapi_handle_ops_isowned (handle) == TRUE)) ||
1182                    (_WAPI_SHARED_HANDLE(type) &&
1183                     WAPI_SHARED_HANDLE_METADATA(handle).signalled == TRUE) ||
1184                    (!_WAPI_SHARED_HANDLE(type) &&
1185                     _WAPI_PRIVATE_HANDLES(idx).signalled == TRUE)) {
1186                         count++;
1187                         
1188 #ifdef DEBUG
1189                         g_message ("%s: Handle %p signalled", __func__,
1190                                    handle);
1191 #endif
1192                         if(*lowest>i) {
1193                                 *lowest=i;
1194                         }
1195                 }
1196         }
1197         
1198 #ifdef DEBUG
1199         g_message ("%s: %d event handles signalled", __func__, count);
1200 #endif
1201
1202         if ((waitall == TRUE && count == numhandles) ||
1203             (waitall == FALSE && count > 0)) {
1204                 ret=TRUE;
1205         } else {
1206                 ret=FALSE;
1207         }
1208         
1209 #ifdef DEBUG
1210         g_message ("%s: Returning %d", __func__, ret);
1211 #endif
1212
1213         *retcount=count;
1214         
1215         return(ret);
1216 }
1217
1218 void _wapi_handle_unlock_handles (guint32 numhandles, gpointer *handles)
1219 {
1220         guint32 i;
1221         int thr_ret;
1222         
1223         thr_ret = _wapi_handle_unlock_shared_handles ();
1224         g_assert (thr_ret == 0);
1225         
1226         for(i=0; i<numhandles; i++) {
1227                 gpointer handle = handles[i];
1228                 
1229 #ifdef DEBUG
1230                 g_message ("%s: unlocking handle %p", __func__, handle);
1231 #endif
1232
1233                 thr_ret = _wapi_handle_unlock_handle (handle);
1234                 g_assert (thr_ret == 0);
1235         }
1236 }
1237
1238 static int timedwait_signal_poll_cond (pthread_cond_t *cond, mono_mutex_t *mutex, struct timespec *timeout)
1239 {
1240         struct timespec fake_timeout;
1241         int ret;
1242         
1243         _wapi_calc_timeout (&fake_timeout, 100);
1244         
1245         if (timeout != NULL && ((fake_timeout.tv_sec > timeout->tv_sec) ||
1246            (fake_timeout.tv_sec == timeout->tv_sec &&
1247                 fake_timeout.tv_nsec > timeout->tv_nsec))) {
1248                 /* Real timeout is less than 100ms time */
1249                 ret=mono_cond_timedwait (cond, mutex, timeout);
1250         } else {
1251                 ret=mono_cond_timedwait (cond, mutex, &fake_timeout);
1252
1253                 /* Mask the fake timeout, this will cause
1254                  * another poll if the cond was not really signaled
1255                  */
1256                 if (ret==ETIMEDOUT) {
1257                         ret=0;
1258                 }
1259         }
1260         
1261         return(ret);
1262 }
1263
1264 int _wapi_handle_wait_signal (void)
1265 {
1266         return timedwait_signal_poll_cond (&_wapi_global_signal_cond, &_wapi_global_signal_mutex, NULL);
1267 }
1268
1269 int _wapi_handle_timedwait_signal (struct timespec *timeout)
1270 {
1271         return timedwait_signal_poll_cond (&_wapi_global_signal_cond, &_wapi_global_signal_mutex, timeout);
1272 }
1273
1274 int _wapi_handle_wait_signal_poll_share (void)
1275 {
1276 #ifdef DEBUG
1277         g_message ("%s: poll private and shared handles", __func__);
1278 #endif
1279         
1280         return timedwait_signal_poll_cond (&_wapi_global_signal_cond, &_wapi_global_signal_mutex, NULL);
1281 }
1282
1283 int _wapi_handle_timedwait_signal_poll_share (struct timespec *timeout)
1284 {
1285 #ifdef DEBUG
1286         g_message ("%s: poll private and shared handles", __func__);
1287 #endif
1288         
1289         return timedwait_signal_poll_cond (&_wapi_global_signal_cond, &_wapi_global_signal_mutex, timeout);
1290 }
1291
1292 int _wapi_handle_wait_signal_handle (gpointer handle)
1293 {
1294 #ifdef DEBUG
1295         g_message ("%s: waiting for %p", __func__, handle);
1296 #endif
1297         
1298         return _wapi_handle_timedwait_signal_handle (handle, NULL);
1299 }
1300
1301 int _wapi_handle_timedwait_signal_handle (gpointer handle,
1302                                           struct timespec *timeout)
1303 {
1304 #ifdef DEBUG
1305         g_message ("%s: waiting for %p (type %s)", __func__, handle,
1306                    _wapi_handle_typename[_wapi_handle_type (handle)]);
1307 #endif
1308         
1309         if (_WAPI_SHARED_HANDLE (_wapi_handle_type (handle))) {
1310                 if (WAPI_SHARED_HANDLE_METADATA(handle).signalled == TRUE) {
1311                         return (0);
1312                 }
1313                 if (timeout != NULL) {
1314                         struct timespec fake_timeout;
1315                         _wapi_calc_timeout (&fake_timeout, 100);
1316                 
1317                         if ((fake_timeout.tv_sec > timeout->tv_sec) ||
1318                                 (fake_timeout.tv_sec == timeout->tv_sec &&
1319                                  fake_timeout.tv_nsec > timeout->tv_nsec)) {
1320                                 /* FIXME: Real timeout is less than
1321                                  * 100ms time, but is it really worth
1322                                  * calculating to the exact ms?
1323                                  */
1324                                 _wapi_handle_spin (100);
1325
1326                                 if (WAPI_SHARED_HANDLE_METADATA(handle).signalled == TRUE) {
1327                                         return (0);
1328                                 } else {
1329                                         return (ETIMEDOUT);
1330                                 }
1331                         }
1332                 }
1333                 _wapi_handle_spin (100);
1334                 return (0);
1335                 
1336         } else {
1337                 guint32 idx = GPOINTER_TO_UINT(handle);
1338                 return timedwait_signal_poll_cond (&_WAPI_PRIVATE_HANDLES(idx).signal_cond, &_WAPI_PRIVATE_HANDLES(idx).signal_mutex, timeout);
1339         }
1340 }
1341
1342 gboolean _wapi_handle_get_or_set_share (dev_t device, ino_t inode,
1343                                         guint32 new_sharemode,
1344                                         guint32 new_access,
1345                                         guint32 *old_sharemode,
1346                                         guint32 *old_access,
1347                                         struct _WapiFileShare **share_info)
1348 {
1349         struct _WapiFileShare *file_share;
1350         guint32 now = (guint32)(time(NULL) & 0xFFFFFFFF);
1351         int thr_ret, i, first_unused = -1;
1352         gboolean exists = FALSE;
1353         
1354         /* Marking this as COLLECTION_UNSAFE prevents entries from
1355          * expiring under us as we search
1356          */
1357         _WAPI_HANDLE_COLLECTION_UNSAFE;
1358         
1359         /* Prevent new entries racing with us */
1360         thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_SHARE);
1361         g_assert (thr_ret == 0);
1362         
1363         /* If a linear scan gets too slow we'll have to fit a hash
1364          * table onto the shared mem backing store
1365          */
1366         *share_info = NULL;
1367         for (i = 0; i <= _wapi_fileshare_layout->hwm; i++) {
1368                 file_share = &_wapi_fileshare_layout->share_info[i];
1369
1370                 /* Make a note of an unused slot, in case we need to
1371                  * store share info
1372                  */
1373                 if (first_unused == -1 && file_share->handle_refs == 0) {
1374                         first_unused = i;
1375                         continue;
1376                 }
1377                 
1378                 if (file_share->handle_refs == 0) {
1379                         continue;
1380                 }
1381                 
1382                 if (file_share->device == device &&
1383                     file_share->inode == inode) {
1384                         *old_sharemode = file_share->sharemode;
1385                         *old_access = file_share->access;
1386                         *share_info = file_share;
1387                         
1388                         /* Increment the reference count while we
1389                          * still have sole access to the shared area.
1390                          * This makes the increment atomic wrt
1391                          * collections
1392                          */
1393                         InterlockedIncrement (&file_share->handle_refs);
1394                         
1395                         exists = TRUE;
1396                         break;
1397                 }
1398         }
1399         
1400         if (!exists) {
1401                 if (i == _WAPI_FILESHARE_SIZE && first_unused == -1) {
1402                         /* No more space */
1403                 } else {
1404                         if (first_unused == -1) {
1405                                 file_share = &_wapi_fileshare_layout->share_info[++i];
1406                                 _wapi_fileshare_layout->hwm = i;
1407                         } else {
1408                                 file_share = &_wapi_fileshare_layout->share_info[first_unused];
1409                         }
1410                         
1411                         file_share->device = device;
1412                         file_share->inode = inode;
1413                         file_share->opened_by_pid = getpid ();
1414                         file_share->sharemode = new_sharemode;
1415                         file_share->access = new_access;
1416                         file_share->handle_refs = 1;
1417                         *share_info = file_share;
1418                 }
1419         }
1420
1421         if (*share_info != NULL) {
1422                 InterlockedExchange (&(*share_info)->timestamp, now);
1423         }
1424         
1425         thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_SHARE);
1426
1427         _WAPI_HANDLE_COLLECTION_SAFE;
1428
1429         return(exists);
1430 }
1431
1432 /* If we don't have the info in /proc, check if the process that
1433  * opened this share info is still there (it's not a perfect method,
1434  * due to pid reuse)
1435  */
1436 static void _wapi_handle_check_share_by_pid (struct _WapiFileShare *share_info)
1437 {
1438         if (kill (share_info->opened_by_pid, 0) == -1 &&
1439             (errno == ESRCH ||
1440              errno == EPERM)) {
1441                 /* It's gone completely (or there's a new process
1442                  * owned by someone else) so mark this share info as
1443                  * dead
1444                  */
1445 #ifdef DEBUG
1446                 g_message ("%s: Didn't find it, destroying entry", __func__);
1447 #endif
1448
1449                 memset (share_info, '\0', sizeof(struct _WapiFileShare));
1450         }
1451 }
1452
1453 /* Scan /proc/<pids>/fd/ for open file descriptors to the file in
1454  * question.  If there are none, reset the share info.
1455  *
1456  * This implementation is Linux-specific; legacy systems will have to
1457  * implement their own ways of finding out if a particular file is
1458  * open by a process.
1459  */
1460 void _wapi_handle_check_share (struct _WapiFileShare *share_info, int fd)
1461 {
1462         gboolean found = FALSE, proc_fds = FALSE;
1463         pid_t self = getpid();
1464         int pid;
1465         int thr_ret, i;
1466         
1467         /* If there is no /proc, there's nothing more we can do here */
1468         if (access ("/proc", F_OK) == -1) {
1469                 _wapi_handle_check_share_by_pid (share_info);
1470                 return;
1471         }
1472         
1473         /* Marking this as COLLECTION_UNSAFE prevents entries from
1474          * expiring under us if we remove this one
1475          */
1476         _WAPI_HANDLE_COLLECTION_UNSAFE;
1477         
1478         /* Prevent new entries racing with us */
1479         thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_SHARE);
1480         g_assert (thr_ret == 0);
1481
1482         for (i = 0; i < _WAPI_HANDLE_INITIAL_COUNT; i++) {
1483                 struct _WapiHandleShared *shared;
1484                 struct _WapiHandleSharedMetadata *meta;
1485                 struct _WapiHandle_process *process_handle;
1486
1487                 meta = &_wapi_shared_layout->metadata[i];
1488                 shared = &_wapi_shared_layout->handles[meta->offset];
1489                 
1490                 if (shared->type == WAPI_HANDLE_PROCESS) {
1491                         DIR *fd_dir;
1492                         struct dirent *fd_entry;
1493                         char subdir[_POSIX_PATH_MAX];
1494
1495                         process_handle = &shared->u.process;
1496                         pid = process_handle->id;
1497                 
1498                         /* Look in /proc/<pid>/fd/ but ignore
1499                          * /proc/<our pid>/fd/<fd>, as we have the
1500                          * file open too
1501                          */
1502                         g_snprintf (subdir, _POSIX_PATH_MAX, "/proc/%d/fd",
1503                                     pid);
1504                         
1505                         fd_dir = opendir (subdir);
1506                         if (fd_dir == NULL) {
1507                                 continue;
1508                         }
1509
1510 #ifdef DEBUG
1511                         g_message ("%s: Looking in %s", __func__, subdir);
1512 #endif
1513                         
1514                         proc_fds = TRUE;
1515                         
1516                         while ((fd_entry = readdir (fd_dir)) != NULL) {
1517                                 char path[_POSIX_PATH_MAX];
1518                                 struct stat link_stat;
1519                                 
1520                                 if (!strcmp (fd_entry->d_name, ".") ||
1521                                     !strcmp (fd_entry->d_name, "..") ||
1522                                     (pid == self &&
1523                                      fd == atoi (fd_entry->d_name))) {
1524                                         continue;
1525                                 }
1526
1527                                 g_snprintf (path, _POSIX_PATH_MAX,
1528                                             "/proc/%d/fd/%s", pid,
1529                                             fd_entry->d_name);
1530                                 
1531                                 stat (path, &link_stat);
1532                                 if (link_stat.st_dev == share_info->device &&
1533                                     link_stat.st_ino == share_info->inode) {
1534 #ifdef DEBUG
1535                                         g_message ("%s:  Found it at %s",
1536                                                    __func__, path);
1537 #endif
1538
1539                                         found = TRUE;
1540                                 }
1541                         }
1542                         
1543                         closedir (fd_dir);
1544                 }
1545         }
1546
1547         if (proc_fds == FALSE) {
1548                 _wapi_handle_check_share_by_pid (share_info);
1549         } else if (found == FALSE) {
1550                 /* Blank out this entry, as it is stale */
1551 #ifdef DEBUG
1552                 g_message ("%s: Didn't find it, destroying entry", __func__);
1553 #endif
1554
1555                 memset (share_info, '\0', sizeof(struct _WapiFileShare));
1556         }
1557
1558         thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_SHARE);
1559
1560         _WAPI_HANDLE_COLLECTION_SAFE;
1561 }
1562
1563 void _wapi_handle_dump (void)
1564 {
1565         struct _WapiHandleUnshared *handle_data;
1566         guint32 i, k;
1567
1568         for(i = SLOT_INDEX (0); _wapi_private_handles [i] != NULL; i++) {
1569                 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
1570                         handle_data = &_wapi_private_handles [i][k];
1571
1572                         if (handle_data->type == WAPI_HANDLE_UNUSED) {
1573                                 continue;
1574                         }
1575                 
1576                         g_print ("%3x [%7s] %s %d ",
1577                                  i * _WAPI_HANDLE_INITIAL_COUNT + k,
1578                                  _wapi_handle_typename[handle_data->type],
1579                                  handle_data->signalled?"Sg":"Un",
1580                                  handle_data->ref);
1581                         handle_details[handle_data->type](&handle_data->u);
1582                         g_print ("\n");
1583                 }
1584         }
1585 }
1586
1587 static void _wapi_shared_details (gpointer handle_info)
1588 {
1589         struct _WapiHandle_shared_ref *shared = (struct _WapiHandle_shared_ref *)handle_info;
1590         
1591         g_print ("offset: 0x%x", shared->offset);
1592 }
1593
1594 void _wapi_handle_update_refs (void)
1595 {
1596         guint32 i, k;
1597         int thr_ret;
1598         
1599         _WAPI_HANDLE_COLLECTION_UNSAFE;
1600
1601         /* Prevent file share entries racing with us */
1602         thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_SHARE);
1603         g_assert(thr_ret == 0);
1604
1605         for(i = SLOT_INDEX (0); _wapi_private_handles [i] != NULL; i++) {
1606                 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
1607                         struct _WapiHandleUnshared *handle = &_wapi_private_handles [i][k];
1608                         guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
1609
1610                         if (_WAPI_SHARED_HANDLE(handle->type)) {
1611                                 struct _WapiHandleSharedMetadata *shared_meta;
1612                                 
1613 #ifdef DEBUG
1614                                 g_message ("%s: (%d) handle 0x%x is SHARED (%s)", __func__,
1615                                            getpid (), i * _WAPI_HANDLE_INITIAL_COUNT + k, _wapi_handle_typename[handle->type]);
1616 #endif
1617
1618                                 shared_meta = &_wapi_shared_layout->metadata[handle->u.shared.offset];
1619
1620 #ifdef DEBUG
1621                                 g_message ("%s: (%d) Updating timestamp of handle 0x%x",
1622                                            __func__, getpid(),
1623                                            handle->u.shared.offset);
1624 #endif
1625
1626                                 InterlockedExchange (&shared_meta->timestamp, now);
1627                         } else if (handle->type == WAPI_HANDLE_FILE) {
1628                                 struct _WapiHandle_file *file_handle = &handle->u.file;
1629                                 
1630 #ifdef DEBUG
1631                                 g_message ("%s: (%d) handle 0x%x is FILE", __func__,
1632                                            getpid (), i * _WAPI_HANDLE_INITIAL_COUNT + k);
1633 #endif
1634                                 
1635                                 g_assert (file_handle->share_info != NULL);
1636
1637 #ifdef DEBUG
1638                                 g_message ("%s: (%d) Inc refs on fileshare 0x%x",
1639                                            __func__, getpid(),
1640                                            (file_handle->share_info - &_wapi_fileshare_layout->share_info[0]) / sizeof(struct _WapiFileShare));
1641 #endif
1642
1643                                 InterlockedExchange (&file_handle->share_info->timestamp, now);
1644                         }
1645                 }
1646         }
1647         
1648         thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_SHARE);
1649
1650         _WAPI_HANDLE_COLLECTION_SAFE;
1651 }