2 * handles.c: Generic and internal operations on handles
5 * Dick Porter (dick@ximian.com)
7 * (C) 2002 Ximian, Inc.
15 #include <sys/types.h>
16 #include <sys/socket.h>
19 #include <mono/os/gc_wrapper.h>
21 #include <mono/io-layer/wapi.h>
22 #include <mono/io-layer/wapi-private.h>
23 #include <mono/io-layer/handles-private.h>
24 #include <mono/io-layer/mono-mutex.h>
25 #include <mono/io-layer/shared.h>
26 #include <mono/io-layer/misc-private.h>
27 #include <mono/io-layer/daemon-messages.h>
31 /* Shared threads don't seem to work yet */
32 #undef _POSIX_THREAD_PROCESS_SHARED
35 * This flag _MUST_ remain set to FALSE in the daemon process. When
36 * we exec()d a standalone daemon, that happened because shared_init()
37 * didnt get called in the daemon process. Now we just fork() without
38 * exec(), we need to ensure that the fork() happens when shared is
41 * This is further complicated by the second attempt to start the
42 * daemon if the connect() fails.
44 static gboolean shared=FALSE;
46 static WapiHandleCapability handle_caps[WAPI_HANDLE_COUNT]={0};
47 static struct _WapiHandleOps *handle_ops[WAPI_HANDLE_COUNT]={
61 static int daemon_sock;
63 static pthread_mutexattr_t mutex_shared_attr;
64 static pthread_condattr_t cond_shared_attr;
66 struct _WapiHandleShared_list *_wapi_shared_data=NULL;
67 struct _WapiHandlePrivate_list *_wapi_private_data=NULL;
69 static void shared_init (void)
71 struct sockaddr_un shared_socket_address;
72 gboolean tried_once=FALSE;
77 #ifndef DISABLE_SHARED_HANDLES
78 if(getenv ("MONO_DISABLE_SHM"))
82 #ifndef DISABLE_SHARED_HANDLES
86 /* Ensure that shared==FALSE while _wapi_shm_attach()
91 _wapi_shared_data=_wapi_shm_attach (&success);
94 g_warning ("Failed to attach shared memory! "
95 "Falling back to non-shared handles");
97 #endif /* DISABLE_SHARED_HANDLES */
102 daemon_sock=socket (PF_UNIX, SOCK_STREAM, 0);
103 shared_socket_address.sun_family=AF_UNIX;
104 memcpy (shared_socket_address.sun_path,
105 _wapi_shared_data->daemon, MONO_SIZEOF_SUNPATH);
106 ret=connect (daemon_sock, (struct sockaddr *)&shared_socket_address,
107 sizeof(struct sockaddr_un));
109 if(tried_once==TRUE) {
110 g_warning (G_GNUC_PRETTY_FUNCTION
111 ": connect to daemon failed: %s",
113 /* Fall back to private handles */
116 /* It's possible that the daemon
117 * crashed without destroying the
118 * shared memory segment (thus fooling
119 * subsequent processes into thinking
120 * the daemon is still active).
122 * Destroy the shared memory segment
123 * and try once more. This won't
124 * break running apps, but no new apps
125 * will be able to see the current
126 * shared memory segment.
129 _wapi_shm_destroy ();
138 g_message (G_GNUC_PRETTY_FUNCTION
139 ": Using process-private handles");
142 g_malloc0 (sizeof(struct _WapiHandleShared_list)+
143 _WAPI_SHM_SCRATCH_SIZE);
145 _wapi_private_data=g_new0 (struct _WapiHandlePrivate_list, 1);
147 pthread_mutexattr_init (&mutex_shared_attr);
148 pthread_condattr_init (&cond_shared_attr);
150 #if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
151 pthread_mutexattr_setpshared (&mutex_shared_attr,
152 PTHREAD_PROCESS_SHARED);
153 pthread_condattr_setpshared (&cond_shared_attr,
154 PTHREAD_PROCESS_SHARED);
159 * _wapi_handle_new_internal:
160 * @type: Init handle to this type
162 * Search for a free handle and initialize it. Return the handle on
163 * succes and 0 on failure.
165 guint32 _wapi_handle_new_internal (WapiHandleType type)
168 static guint32 last=1;
170 /* A linear scan should be fast enough. Start from the last
171 * allocation, assuming that handles are allocated more often
172 * than they're freed. Leave 0 (NULL) as a guard
175 for(i=last; i<_WAPI_MAX_HANDLES; i++) {
176 struct _WapiHandleShared *shared=&_wapi_shared_data->handles[i];
178 if(shared->type==WAPI_HANDLE_UNUSED) {
181 shared->signalled=FALSE;
182 #if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
183 mono_mutex_init (&_wapi_shared_data->handles[i].signal_mutex, &mutex_shared_attr);
184 pthread_cond_init (&_wapi_shared_data->handles[i].signal_cond, &cond_shared_attr);
192 /* Try again from the beginning */
200 gpointer _wapi_handle_new (WapiHandleType type)
202 static mono_once_t shared_init_once = MONO_ONCE_INIT;
203 static pthread_mutex_t scan_mutex=PTHREAD_MUTEX_INITIALIZER;
206 WapiHandleRequest new;
207 WapiHandleResponse new_resp;
209 gboolean tried_collect=FALSE;
212 mono_once (&shared_init_once, shared_init);
216 new.type=WapiHandleRequestType_New;
219 _wapi_daemon_request_response (daemon_sock, &new, &new_resp);
221 if (new_resp.type==WapiHandleResponseType_New) {
222 idx=new_resp.u.new.handle;
224 g_warning (G_GNUC_PRETTY_FUNCTION
225 ": bogus daemon response, type %d",
227 g_assert_not_reached ();
230 pthread_mutex_lock (&scan_mutex);
231 idx=_wapi_handle_new_internal (type);
232 _wapi_shared_data->handles[idx].ref++;
233 pthread_mutex_unlock (&scan_mutex);
237 g_warning (G_GNUC_PRETTY_FUNCTION ": Ran out of handles!");
240 /* See if we can reclaim some handles by forcing a GC
243 if(tried_collect==FALSE) {
244 g_warning (G_GNUC_PRETTY_FUNCTION
245 ": Seeing if GC collection helps...");
250 g_warning (G_GNUC_PRETTY_FUNCTION
251 ": didn't help, returning error");
255 return(GUINT_TO_POINTER (_WAPI_HANDLE_INVALID));
258 #if !defined(_POSIX_THREAD_PROCESS_SHARED) || _POSIX_THREAD_PROCESS_SHARED == -1
259 mono_mutex_init (&_wapi_shared_data->handles[idx].signal_mutex, &mutex_shared_attr);
260 pthread_cond_init (&_wapi_shared_data->handles[idx].signal_cond, &cond_shared_attr);
262 handle=GUINT_TO_POINTER (idx);
265 g_message (G_GNUC_PRETTY_FUNCTION ": Allocated new handle %p", handle);
271 gboolean _wapi_lookup_handle (gpointer handle, WapiHandleType type,
272 gpointer *shared, gpointer *private)
274 struct _WapiHandleShared *shared_handle_data;
275 struct _WapiHandlePrivate *private_handle_data;
276 guint32 idx=GPOINTER_TO_UINT (handle);
278 shared_handle_data=&_wapi_shared_data->handles[idx];
280 if(shared_handle_data->type!=type) {
285 *shared=&shared_handle_data->u;
289 private_handle_data=&_wapi_private_data->handles[idx];
291 *private=&private_handle_data->u;
297 gpointer _wapi_search_handle (WapiHandleType type,
298 gboolean (*check)(gpointer test, gpointer user),
300 gpointer *shared, gpointer *private)
302 struct _WapiHandleShared *shared_handle_data;
303 struct _WapiHandlePrivate *private_handle_data;
306 for(i=1; i<_WAPI_MAX_HANDLES; i++) {
307 struct _WapiHandleShared *shared=&_wapi_shared_data->handles[i];
309 if(shared->type==type) {
310 if(check (GUINT_TO_POINTER (i), user_data)==TRUE) {
316 if(i==_WAPI_MAX_HANDLES) {
317 return(GUINT_TO_POINTER (0));
321 shared_handle_data=&_wapi_shared_data->handles[i];
323 *shared=&shared_handle_data->u;
327 private_handle_data=&_wapi_private_data->handles[i];
329 *private=&private_handle_data->u;
332 return(GUINT_TO_POINTER (i));
335 void _wapi_handle_ref (gpointer handle)
337 guint32 idx=GPOINTER_TO_UINT (handle);
340 WapiHandleRequest req;
341 WapiHandleResponse resp;
343 req.type=WapiHandleRequestType_Open;
344 req.u.open.handle=idx;
346 _wapi_daemon_request_response (daemon_sock, &req, &resp);
347 if(resp.type!=WapiHandleResponseType_Open) {
348 g_warning (G_GNUC_PRETTY_FUNCTION
349 ": bogus daemon response, type %d",
351 g_assert_not_reached ();
354 _wapi_shared_data->handles[idx].ref++;
357 g_message (G_GNUC_PRETTY_FUNCTION ": handle %p ref now %d",
358 handle, _wapi_shared_data->handles[idx].ref);
363 void _wapi_handle_unref (gpointer handle)
365 guint32 idx=GPOINTER_TO_UINT (handle);
369 WapiHandleRequest req;
370 WapiHandleResponse resp;
372 req.type=WapiHandleRequestType_Close;
373 req.u.close.handle=GPOINTER_TO_UINT (handle);
375 _wapi_daemon_request_response (daemon_sock, &req, &resp);
376 if(resp.type!=WapiHandleResponseType_Close) {
377 g_warning (G_GNUC_PRETTY_FUNCTION
378 ": bogus daemon response, type %d",
380 g_assert_not_reached ();
382 destroy=resp.u.close.destroy;
385 _wapi_shared_data->handles[idx].ref--;
388 g_message (G_GNUC_PRETTY_FUNCTION ": handle %p ref now %d",
389 handle, _wapi_shared_data->handles[idx].ref);
392 /* Possible race condition here if another thread refs
393 * the handle between here and setting the type to
394 * UNUSED. I could lock a mutex, but I'm not sure
395 * that allowing a handle reference to reach 0 isn't
396 * an application bug anyway.
398 destroy=(_wapi_shared_data->handles[idx].ref==0);
403 g_message (G_GNUC_PRETTY_FUNCTION ": Destroying handle %p",
408 _wapi_handle_ops_close_shared (handle);
410 mono_mutex_destroy (&_wapi_shared_data->handles[idx].signal_mutex);
411 pthread_cond_destroy (&_wapi_shared_data->handles[idx].signal_cond);
412 memset (&_wapi_shared_data->handles[idx].u, '\0', sizeof(_wapi_shared_data->handles[idx].u));
415 #if !defined(_POSIX_THREAD_PROCESS_SHARED) || _POSIX_THREAD_PROCESS_SHARED == -1
417 mono_mutex_destroy (&_wapi_shared_data->handles[idx].signal_mutex);
418 pthread_cond_destroy (&_wapi_shared_data->handles[idx].signal_cond);
422 _wapi_handle_ops_close_private (handle);
423 _wapi_shared_data->handles[idx].type=WAPI_HANDLE_UNUSED;
427 #define HDRSIZE sizeof(struct _WapiScratchHeader)
430 * _wapi_handle_scratch_store_internal:
431 * @bytes: Allocate no. bytes
433 * Like malloc(3) except its for the shared memory segment's scratch
434 * part. Memory block returned is zeroed out.
436 guint32 _wapi_handle_scratch_store_internal (guint32 bytes)
438 guint32 idx=0, last_idx=0;
439 struct _WapiScratchHeader *hdr, *last_hdr;
440 gboolean last_was_free=FALSE;
441 guchar *storage=&_wapi_shared_data->scratch_base[0];
444 g_message (G_GNUC_PRETTY_FUNCTION
445 ": looking for %d bytes of scratch space (%d bytes total)",
446 bytes, _WAPI_SHM_SCRATCH_SIZE);
449 hdr=(struct _WapiScratchHeader *)&storage[0];
450 if(hdr->flags==0 && hdr->length==0) {
451 /* Need to initialise scratch data */
452 hdr->flags |= WAPI_SHM_SCRATCH_FREE;
453 hdr->length = _WAPI_SHM_SCRATCH_SIZE - HDRSIZE;
456 while(idx< _WAPI_SHM_SCRATCH_SIZE) {
457 hdr=(struct _WapiScratchHeader *)&storage[idx];
459 /* Do a simple first-fit allocation, coalescing
460 * adjacent free blocks as we progress through the
463 if(hdr->flags & WAPI_SHM_SCRATCH_FREE &&
464 hdr->length >= bytes + HDRSIZE) {
466 guint32 old_length=hdr->length;
468 g_message (G_GNUC_PRETTY_FUNCTION ": found suitable free size at %d, length %d", idx, hdr->length);
471 hdr->flags &= ~WAPI_SHM_SCRATCH_FREE;
475 /* Put a new header in at the end of the used
478 hdr=(struct _WapiScratchHeader *)&storage[idx+bytes];
479 hdr->flags |= WAPI_SHM_SCRATCH_FREE;
480 hdr->length = old_length-bytes-HDRSIZE;
483 g_message (G_GNUC_PRETTY_FUNCTION ": new header at %d, length %d", idx+bytes, hdr->length);
487 * It was memset(0..) when free/made so no need to do it here
491 } else if(hdr->flags & WAPI_SHM_SCRATCH_FREE &&
492 last_was_free == FALSE) {
494 g_message (G_GNUC_PRETTY_FUNCTION ": found too-small free block at %d, length %d (previous used)", idx, hdr->length);
497 /* save this point in case we can coalesce it with
498 * the next block, if that is free.
503 idx+=(hdr->length+HDRSIZE);
504 } else if (hdr->flags & WAPI_SHM_SCRATCH_FREE &&
505 last_was_free == TRUE) {
507 g_message (G_GNUC_PRETTY_FUNCTION ": found too-small free block at %d, length %d (previous free)", idx, hdr->length);
510 /* This block and the previous are both free,
513 last_hdr->length += (hdr->length + HDRSIZE);
515 /* If the new block is now big enough, use it
516 * (next time round the loop)
518 if(last_hdr->length >= bytes + HDRSIZE) {
521 /* leave the last free info as it is,
522 * in case the next block is also free
523 * and can be coalesced too
525 idx=last_idx+last_hdr->length+HDRSIZE;
529 g_message (G_GNUC_PRETTY_FUNCTION
530 ": found used block at %d, length %d", idx,
534 /* must be used, try next chunk */
535 idx+=(hdr->length+HDRSIZE);
537 /* Don't let the coalescing blow away this block */
545 guint32 _wapi_handle_scratch_store (gconstpointer data, guint32 bytes)
547 static pthread_mutex_t scratch_mutex=PTHREAD_MUTEX_INITIALIZER;
550 /* No point storing no data */
555 /* Align bytes to 32 bits (needed for sparc at least) */
556 bytes = (((bytes) + 3) & (~3));
559 WapiHandleRequest scratch;
560 WapiHandleResponse scratch_resp;
562 scratch.type=WapiHandleRequestType_Scratch;
563 scratch.u.scratch.length=bytes;
565 _wapi_daemon_request_response (daemon_sock, &scratch,
568 if(scratch_resp.type==WapiHandleResponseType_Scratch) {
569 idx=scratch_resp.u.scratch.idx;
571 g_warning (G_GNUC_PRETTY_FUNCTION
572 ": bogus daemon response, type %d",
574 g_assert_not_reached ();
577 pthread_mutex_lock (&scratch_mutex);
578 idx=_wapi_handle_scratch_store_internal (bytes);
579 pthread_mutex_unlock (&scratch_mutex);
582 /* Failed to allocate space */
588 g_message (G_GNUC_PRETTY_FUNCTION ": stored [%s] at %d (len %d)",
589 (char *)data, idx, bytes);
592 memcpy (&_wapi_shared_data->scratch_base[idx], data, bytes);
597 guint32 _wapi_handle_scratch_store_string_array (gchar **data)
599 guint32 *stored_strings, count=0, i, idx;
602 /* No point storing no data */
608 while(*strings!=NULL) {
614 g_message (G_GNUC_PRETTY_FUNCTION ": %d strings to store", count);
621 /* stored_strings[0] is the count */
622 stored_strings=g_new0 (guint32, count+1);
623 stored_strings[0]=count;
626 for(i=0; i<count; i++) {
627 stored_strings[i+1]=_wapi_handle_scratch_store (strings[i], strlen (strings[i]));
630 idx=_wapi_handle_scratch_store (stored_strings,
631 sizeof(guint32)*(count+1));
636 guchar *_wapi_handle_scratch_lookup_as_string (guint32 idx)
638 struct _WapiScratchHeader *hdr;
640 guchar *storage=&_wapi_shared_data->scratch_base[0];
642 if(idx < HDRSIZE || idx > _WAPI_SHM_SCRATCH_SIZE) {
646 hdr=(struct _WapiScratchHeader *)&storage[idx - HDRSIZE];
647 str=g_malloc0 (hdr->length+1);
648 memcpy (str, &storage[idx], hdr->length);
653 gconstpointer _wapi_handle_scratch_lookup (guint32 idx)
655 guchar *storage=&_wapi_shared_data->scratch_base[0];
657 if(idx < HDRSIZE || idx > _WAPI_SHM_SCRATCH_SIZE) {
661 return(&storage[idx]);
664 gchar **_wapi_handle_scratch_lookup_string_array (guint32 idx)
667 const guint32 *stored_strings;
670 if(idx < HDRSIZE || idx > _WAPI_SHM_SCRATCH_SIZE) {
674 stored_strings=_wapi_handle_scratch_lookup (idx);
675 if(stored_strings==NULL) {
679 /* stored_strings[0] is the number of strings, the index of
680 * each string follows
682 count=stored_strings[0];
685 g_message (G_GNUC_PRETTY_FUNCTION
686 ": looking up an array of %d strings", count);
689 /* NULL-terminate the array */
690 strings=g_new0 (gchar *, count+1);
692 for(i=0; i<count; i++) {
693 strings[i]=_wapi_handle_scratch_lookup_as_string (stored_strings[i+1]);
696 g_message (G_GNUC_PRETTY_FUNCTION ": string %d is [%s]", i,
705 * _wapi_handle_scratch_delete_internal:
706 * @idx: Index to free block
708 * Like free(3) except its for the shared memory segment's scratch
711 void _wapi_handle_scratch_delete_internal (guint32 idx)
713 struct _WapiScratchHeader *hdr;
714 guchar *storage=&_wapi_shared_data->scratch_base[0];
716 if(idx < HDRSIZE || idx > _WAPI_SHM_SCRATCH_SIZE) {
720 hdr=(struct _WapiScratchHeader *)&storage[idx - HDRSIZE];
721 memset (&storage[idx], '\0', hdr->length);
722 hdr->flags |= WAPI_SHM_SCRATCH_FREE;
724 /* We could coalesce forwards here if the next block is also
725 * free, but the _store() function will do that anyway.
729 void _wapi_handle_scratch_delete (guint32 idx)
732 WapiHandleRequest scratch_free;
733 WapiHandleResponse scratch_free_resp;
735 scratch_free.type=WapiHandleRequestType_ScratchFree;
736 scratch_free.u.scratch_free.idx=idx;
738 _wapi_daemon_request_response (daemon_sock, &scratch_free,
741 if(scratch_free_resp.type!=WapiHandleResponseType_ScratchFree) {
742 g_warning (G_GNUC_PRETTY_FUNCTION
743 ": bogus daemon response, type %d",
744 scratch_free_resp.type);
745 g_assert_not_reached ();
748 _wapi_handle_scratch_delete_internal (idx);
752 void _wapi_handle_scratch_delete_string_array (guint32 idx)
754 const guint32 *stored_strings;
757 stored_strings=_wapi_handle_scratch_lookup (idx);
758 if(stored_strings==NULL) {
762 /* stored_strings[0] is the number of strings, the index of
763 * each string follows
765 count=stored_strings[0];
768 g_message (G_GNUC_PRETTY_FUNCTION ": deleting an array of %d strings",
772 for(i=1; i<count; i++) {
773 _wapi_handle_scratch_delete (stored_strings[i]);
776 _wapi_handle_scratch_delete (idx);
779 void _wapi_handle_register_capabilities (WapiHandleType type,
780 WapiHandleCapability caps)
782 handle_caps[type]=caps;
785 gboolean _wapi_handle_test_capabilities (gpointer handle,
786 WapiHandleCapability caps)
788 guint32 idx=GPOINTER_TO_UINT (handle);
791 type=_wapi_shared_data->handles[idx].type;
794 g_message (G_GNUC_PRETTY_FUNCTION ": testing 0x%x against 0x%x (%d)",
795 handle_caps[type], caps, handle_caps[type] & caps);
798 return((handle_caps[type] & caps)!=0);
801 void _wapi_handle_ops_close_shared (gpointer handle)
803 guint32 idx=GPOINTER_TO_UINT (handle);
806 type=_wapi_shared_data->handles[idx].type;
808 if(handle_ops[type]!=NULL && handle_ops[type]->close_shared!=NULL) {
809 handle_ops[type]->close_shared (handle);
813 void _wapi_handle_ops_close_private (gpointer handle)
815 guint32 idx=GPOINTER_TO_UINT (handle);
818 type=_wapi_shared_data->handles[idx].type;
820 if(handle_ops[type]!=NULL && handle_ops[type]->close_private!=NULL) {
821 handle_ops[type]->close_private (handle);
825 void _wapi_handle_ops_signal (gpointer handle)
827 guint32 idx=GPOINTER_TO_UINT (handle);
830 type=_wapi_shared_data->handles[idx].type;
832 if(handle_ops[type]!=NULL && handle_ops[type]->signal!=NULL) {
833 handle_ops[type]->signal (handle);
837 void _wapi_handle_ops_own (gpointer handle)
839 guint32 idx=GPOINTER_TO_UINT (handle);
842 type=_wapi_shared_data->handles[idx].type;
844 if(handle_ops[type]!=NULL && handle_ops[type]->own_handle!=NULL) {
845 handle_ops[type]->own_handle (handle);
849 gboolean _wapi_handle_ops_isowned (gpointer handle)
851 guint32 idx=GPOINTER_TO_UINT (handle);
854 type=_wapi_shared_data->handles[idx].type;
856 if(handle_ops[type]!=NULL && handle_ops[type]->is_owned!=NULL) {
857 return(handle_ops[type]->is_owned (handle));
865 * @handle: The handle to release
867 * Closes and invalidates @handle, releasing any resources it
868 * consumes. When the last handle to a temporary or non-persistent
869 * object is closed, that object can be deleted. Closing the same
870 * handle twice is an error.
872 * Return value: %TRUE on success, %FALSE otherwise.
874 gboolean CloseHandle(gpointer handle)
876 _wapi_handle_unref (handle);
881 gboolean _wapi_handle_count_signalled_handles (guint32 numhandles,
887 guint32 count, i, iter=0;
890 /* Lock all the handles, with backoff */
892 for(i=0; i<numhandles; i++) {
893 guint32 idx=GPOINTER_TO_UINT (handles[i]);
896 g_message (G_GNUC_PRETTY_FUNCTION ": attempting to lock %p",
900 ret=mono_mutex_trylock (&_wapi_shared_data->handles[idx].signal_mutex);
903 struct timespec sleepytime;
906 g_message (G_GNUC_PRETTY_FUNCTION ": attempt failed for %p", handles[i]);
910 idx=GPOINTER_TO_UINT (handles[i]);
911 mono_mutex_unlock (&_wapi_shared_data->handles[idx].signal_mutex);
914 /* If iter ever reaches 100 the nanosleep will
915 * return EINVAL immediately, but we have a
916 * design flaw if that happens.
920 g_warning (G_GNUC_PRETTY_FUNCTION
921 ": iteration overflow!");
926 sleepytime.tv_nsec=10000000 * iter; /* 10ms*iter */
929 g_message (G_GNUC_PRETTY_FUNCTION
930 ": Backing off for %d ms", iter*10);
932 nanosleep (&sleepytime, NULL);
939 g_message (G_GNUC_PRETTY_FUNCTION ": Locked all handles");
945 for(i=0; i<numhandles; i++) {
946 guint32 idx=GPOINTER_TO_UINT (handles[i]);
949 g_message (G_GNUC_PRETTY_FUNCTION ": Checking handle %p",
953 if(((_wapi_handle_test_capabilities (handles[i], WAPI_HANDLE_CAP_OWN)==TRUE) &&
954 (_wapi_handle_ops_isowned (handles[i])==TRUE)) ||
955 (_wapi_shared_data->handles[idx].signalled==TRUE)) {
959 g_message (G_GNUC_PRETTY_FUNCTION
960 ": Handle %p signalled", handles[i]);
969 g_message (G_GNUC_PRETTY_FUNCTION ": %d event handles signalled",
973 if((waitall==TRUE && count==numhandles) ||
974 (waitall==FALSE && count>0)) {
981 g_message (G_GNUC_PRETTY_FUNCTION ": Returning %d", ret);
989 void _wapi_handle_unlock_handles (guint32 numhandles, gpointer *handles)
993 for(i=0; i<numhandles; i++) {
994 guint32 idx=GPOINTER_TO_UINT (handles[i]);
997 g_message (G_GNUC_PRETTY_FUNCTION ": unlocking handle %p",
1001 mono_mutex_unlock (&_wapi_shared_data->handles[idx].signal_mutex);
1005 /* Process-shared handles (currently only process and thread handles
1006 * are allowed, and they only work because once signalled they can't
1007 * become unsignalled) are waited for by one process and signalled by
1008 * another. Without process-shared conditions, the waiting process
1009 * will block forever. To get around this, the four handle waiting
1010 * functions use a short timeout when _POSIX_THREAD_PROCESS_SHARED is
1011 * not available. They also return "success" if the fake timeout
1012 * expired, and let the caller check signal status.
1014 int _wapi_handle_wait_signal (void)
1016 #if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
1017 return(mono_cond_wait (&_wapi_shared_data->signal_cond,
1018 &_wapi_shared_data->signal_mutex));
1020 struct timespec fake_timeout;
1023 _wapi_calc_timeout (&fake_timeout, 100);
1025 ret=mono_cond_timedwait (&_wapi_private_data->signal_cond,
1026 &_wapi_private_data->signal_mutex,
1028 if(ret==ETIMEDOUT) {
1033 #endif /* _POSIX_THREAD_PROCESS_SHARED */
1036 int _wapi_handle_timedwait_signal (struct timespec *timeout)
1038 #if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
1039 return(mono_cond_timedwait (&_wapi_shared_data->signal_cond,
1040 &_wapi_shared_data->signal_mutex,
1043 struct timespec fake_timeout;
1046 _wapi_calc_timeout (&fake_timeout, 100);
1048 if((fake_timeout.tv_sec>timeout->tv_sec) ||
1049 (fake_timeout.tv_sec==timeout->tv_sec &&
1050 fake_timeout.tv_nsec > timeout->tv_nsec)) {
1051 /* Real timeout is less than 100ms time */
1052 ret=mono_cond_timedwait (&_wapi_private_data->signal_cond,
1053 &_wapi_private_data->signal_mutex,
1056 ret=mono_cond_timedwait (&_wapi_private_data->signal_cond,
1057 &_wapi_private_data->signal_mutex,
1059 if(ret==ETIMEDOUT) {
1065 #endif /* _POSIX_THREAD_PROCESS_SHARED */
1068 int _wapi_handle_wait_signal_handle (gpointer handle)
1070 #if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
1071 guint32 idx=GPOINTER_TO_UINT (handle);
1073 return(mono_cond_wait (&_wapi_shared_data->handles[idx].signal_cond,
1074 &_wapi_shared_data->handles[idx].signal_mutex));
1076 guint32 idx=GPOINTER_TO_UINT (handle);
1077 struct timespec fake_timeout;
1080 _wapi_calc_timeout (&fake_timeout, 100);
1082 ret=mono_cond_timedwait (&_wapi_shared_data->handles[idx].signal_cond,
1083 &_wapi_shared_data->handles[idx].signal_mutex,
1085 if(ret==ETIMEDOUT) {
1090 #endif /* _POSIX_THREAD_PROCESS_SHARED */
1093 int _wapi_handle_timedwait_signal_handle (gpointer handle,
1094 struct timespec *timeout)
1096 #if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
1097 guint32 idx=GPOINTER_TO_UINT (handle);
1099 return(mono_cond_timedwait (&_wapi_shared_data->handles[idx].signal_cond,
1100 &_wapi_shared_data->handles[idx].signal_mutex,
1103 guint32 idx=GPOINTER_TO_UINT (handle);
1104 struct timespec fake_timeout;
1107 _wapi_calc_timeout (&fake_timeout, 100);
1109 if((fake_timeout.tv_sec>timeout->tv_sec) ||
1110 (fake_timeout.tv_sec==timeout->tv_sec &&
1111 fake_timeout.tv_nsec > timeout->tv_nsec)) {
1112 /* Real timeout is less than 100ms time */
1113 ret=mono_cond_timedwait (&_wapi_shared_data->handles[idx].signal_cond,
1114 &_wapi_shared_data->handles[idx].signal_mutex,
1117 ret=mono_cond_timedwait (&_wapi_shared_data->handles[idx].signal_cond,
1118 &_wapi_shared_data->handles[idx].signal_mutex,
1120 if(ret==ETIMEDOUT) {
1126 #endif /* _POSIX_THREAD_PROCESS_SHARED */
1129 gboolean _wapi_handle_process_fork (guint32 cmd, guint32 env, guint32 dir,
1130 gboolean inherit, guint32 flags,
1131 gpointer stdin_handle,
1132 gpointer stdout_handle,
1133 gpointer stderr_handle,
1134 gpointer *process_handle,
1135 gpointer *thread_handle, guint32 *pid,
1138 WapiHandleRequest fork_proc;
1139 WapiHandleResponse fork_proc_resp;
1140 int in_fd, out_fd, err_fd;
1146 fork_proc.type=WapiHandleRequestType_ProcessFork;
1147 fork_proc.u.process_fork.cmd=cmd;
1148 fork_proc.u.process_fork.env=env;
1149 fork_proc.u.process_fork.dir=dir;
1150 fork_proc.u.process_fork.stdin_handle=GPOINTER_TO_UINT (stdin_handle);
1151 fork_proc.u.process_fork.stdout_handle=GPOINTER_TO_UINT (stdout_handle);
1152 fork_proc.u.process_fork.stderr_handle=GPOINTER_TO_UINT (stderr_handle);
1153 fork_proc.u.process_fork.inherit=inherit;
1154 fork_proc.u.process_fork.flags=flags;
1156 in_fd=_wapi_file_handle_to_fd (stdin_handle);
1157 out_fd=_wapi_file_handle_to_fd (stdout_handle);
1158 err_fd=_wapi_file_handle_to_fd (stderr_handle);
1160 if(in_fd==-1 || out_fd==-1 || err_fd==-1) {
1161 /* We were given duff handles */
1162 /* FIXME: error code */
1166 _wapi_daemon_request_response_with_fds (daemon_sock, &fork_proc,
1167 &fork_proc_resp, in_fd,
1169 if(fork_proc_resp.type==WapiHandleResponseType_ProcessFork) {
1170 *process_handle=GUINT_TO_POINTER (fork_proc_resp.u.process_fork.process_handle);
1171 *thread_handle=GUINT_TO_POINTER (fork_proc_resp.u.process_fork.thread_handle);
1172 *pid=fork_proc_resp.u.process_fork.pid;
1173 *tid=fork_proc_resp.u.process_fork.tid;
1175 /* If there was an internal error, the handles will be
1176 * 0. If there was an error forking or execing, the
1177 * handles will have values, and process_handle's
1178 * exec_errno will be set, and the handle will be
1179 * signalled immediately.
1181 if(process_handle==0 || thread_handle==0) {
1187 g_warning (G_GNUC_PRETTY_FUNCTION
1188 ": bogus daemon response, type %d",
1189 fork_proc_resp.type);
1190 g_assert_not_reached ();