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>
23 #include <mono/io-layer/wapi.h>
24 #include <mono/io-layer/wapi-private.h>
25 #include <mono/io-layer/handles-private.h>
26 #include <mono/io-layer/mono-mutex.h>
27 #include <mono/io-layer/shared.h>
28 #include <mono/io-layer/misc-private.h>
29 #include <mono/io-layer/daemon-messages.h>
34 * This flag _MUST_ remain set to FALSE in the daemon process. When
35 * we exec()d a standalone daemon, that happened because shared_init()
36 * didnt get called in the daemon process. Now we just fork() without
37 * exec(), we need to ensure that the fork() happens when shared is
40 * This is further complicated by the second attempt to start the
41 * daemon if the connect() fails.
43 static gboolean shared=FALSE;
45 static WapiHandleCapability handle_caps[WAPI_HANDLE_COUNT]={0};
46 static struct _WapiHandleOps *handle_ops[WAPI_HANDLE_COUNT]={
59 static int daemon_sock;
61 static pthread_mutexattr_t mutex_shared_attr;
62 static pthread_condattr_t cond_shared_attr;
64 struct _WapiHandleShared_list *_wapi_shared_data=NULL;
65 struct _WapiHandlePrivate_list *_wapi_private_data=NULL;
68 static void shared_init (void)
70 struct sockaddr_un shared_socket_address;
71 gboolean tried_once=FALSE;
74 if (getenv ("MONO_ENABLE_SHM"))
79 #ifndef DISABLE_SHARED_HANDLES
80 if(getenv ("MONO_DISABLE_SHM") || disable_shm)
84 #ifndef DISABLE_SHARED_HANDLES
89 /* Ensure that shared==FALSE while _wapi_shm_attach()
94 _wapi_shared_data=_wapi_shm_attach (FALSE, &success, &shm_id);
97 g_warning ("Failed to attach shared memory! "
98 "(tried shared memory ID 0x%x). "
99 "Falling back to non-shared handles",
102 #endif /* DISABLE_SHARED_HANDLES */
107 daemon_sock=socket (PF_UNIX, SOCK_STREAM, 0);
108 shared_socket_address.sun_family=AF_UNIX;
109 memcpy (shared_socket_address.sun_path,
110 _wapi_shared_data->daemon, MONO_SIZEOF_SUNPATH);
111 ret=connect (daemon_sock, (struct sockaddr *)&shared_socket_address,
112 sizeof(struct sockaddr_un));
114 if(tried_once==TRUE) {
115 g_warning (G_GNUC_PRETTY_FUNCTION
116 "connect to daemon failed: %s",
118 /* Fall back to private handles */
121 /* It's possible that the daemon
122 * crashed without destroying the
123 * shared memory segment (thus fooling
124 * subsequent processes into thinking
125 * the daemon is still active).
127 * Destroy the shared memory segment
128 * and try once more. This won't
129 * break running apps, but no new apps
130 * will be able to see the current
131 * shared memory segment.
134 _wapi_shm_destroy ();
143 g_message (G_GNUC_PRETTY_FUNCTION
144 ": Using process-private handles");
147 g_malloc0 (sizeof(struct _WapiHandleShared_list)+
148 _WAPI_SHM_SCRATCH_SIZE);
150 _wapi_private_data=g_new0 (struct _WapiHandlePrivate_list, 1);
152 pthread_mutexattr_init (&mutex_shared_attr);
153 pthread_condattr_init (&cond_shared_attr);
155 #ifdef _POSIX_THREAD_PROCESS_SHARED
156 pthread_mutexattr_setpshared (&mutex_shared_attr,
157 PTHREAD_PROCESS_SHARED);
158 pthread_condattr_setpshared (&cond_shared_attr,
159 PTHREAD_PROCESS_SHARED);
164 * _wapi_handle_new_internal:
165 * @type: Init handle to this type
167 * Search for a free handle and initialize it. Return the handle on
168 * succes and 0 on failure.
170 guint32 _wapi_handle_new_internal (WapiHandleType type)
173 static guint32 last=1;
175 /* A linear scan should be fast enough. Start from the last
176 * allocation, assuming that handles are allocated more often
177 * than they're freed. Leave 0 (NULL) as a guard
180 for(i=last; i<_WAPI_MAX_HANDLES; i++) {
181 struct _WapiHandleShared *shared=&_wapi_shared_data->handles[i];
183 if(shared->type==WAPI_HANDLE_UNUSED) {
186 shared->signalled=FALSE;
187 mono_mutex_init (&_wapi_shared_data->handles[i].signal_mutex, &mutex_shared_attr);
188 pthread_cond_init (&_wapi_shared_data->handles[i].signal_cond, &cond_shared_attr);
195 /* Try again from the beginning */
203 gpointer _wapi_handle_new (WapiHandleType type)
205 static mono_once_t shared_init_once = MONO_ONCE_INIT;
206 static pthread_mutex_t scan_mutex=PTHREAD_MUTEX_INITIALIZER;
209 WapiHandleRequest new;
210 WapiHandleResponse new_resp;
212 gboolean tried_collect=FALSE;
215 mono_once (&shared_init_once, shared_init);
219 new.type=WapiHandleRequestType_New;
222 _wapi_daemon_request_response (daemon_sock, &new, &new_resp);
224 if (new_resp.type==WapiHandleResponseType_New) {
225 idx=new_resp.u.new.handle;
227 g_warning (G_GNUC_PRETTY_FUNCTION
228 ": bogus daemon response, type %d",
230 g_assert_not_reached ();
233 pthread_mutex_lock (&scan_mutex);
234 idx=_wapi_handle_new_internal (type);
235 pthread_mutex_unlock (&scan_mutex);
239 g_warning (G_GNUC_PRETTY_FUNCTION ": Ran out of handles!");
242 /* See if we can reclaim some handles by forcing a GC
245 if(tried_collect==FALSE) {
246 g_warning (G_GNUC_PRETTY_FUNCTION
247 ": Seeing if GC collection helps...");
252 g_warning (G_GNUC_PRETTY_FUNCTION
253 ": didn't help, returning error");
257 return(GUINT_TO_POINTER (_WAPI_HANDLE_INVALID));
260 handle=GUINT_TO_POINTER (idx);
263 g_message (G_GNUC_PRETTY_FUNCTION ": Allocated new handle %p", handle);
269 gboolean _wapi_lookup_handle (gpointer handle, WapiHandleType type,
270 gpointer *shared, gpointer *private)
272 struct _WapiHandleShared *shared_handle_data;
273 struct _WapiHandlePrivate *private_handle_data;
274 guint32 idx=GPOINTER_TO_UINT (handle);
276 shared_handle_data=&_wapi_shared_data->handles[idx];
278 /* Allow WAPI_HANDLE_UNUSED to mean "dont care which
281 if(shared_handle_data->type!=type && type != WAPI_HANDLE_UNUSED) {
286 *shared=&shared_handle_data->u;
290 private_handle_data=&_wapi_private_data->handles[idx];
292 *private=&private_handle_data->u;
298 gpointer _wapi_search_handle (WapiHandleType type,
299 gboolean (*check)(gpointer test, gpointer user),
301 gpointer *shared, gpointer *private)
303 struct _WapiHandleShared *shared_handle_data;
304 struct _WapiHandlePrivate *private_handle_data;
307 for(i=1; i<_WAPI_MAX_HANDLES; i++) {
308 struct _WapiHandleShared *shared=&_wapi_shared_data->handles[i];
310 if(shared->type==type) {
311 if(check (GUINT_TO_POINTER (i), user_data)==TRUE) {
317 if(i==_WAPI_MAX_HANDLES) {
318 return(GUINT_TO_POINTER (0));
322 shared_handle_data=&_wapi_shared_data->handles[i];
324 *shared=&shared_handle_data->u;
328 private_handle_data=&_wapi_private_data->handles[i];
330 *private=&private_handle_data->u;
333 return(GUINT_TO_POINTER (i));
336 void _wapi_handle_ref (gpointer handle)
338 guint32 idx=GPOINTER_TO_UINT (handle);
341 WapiHandleRequest req;
342 WapiHandleResponse resp;
344 req.type=WapiHandleRequestType_Open;
345 req.u.open.handle=idx;
347 _wapi_daemon_request_response (daemon_sock, &req, &resp);
348 if(resp.type!=WapiHandleResponseType_Open) {
349 g_warning (G_GNUC_PRETTY_FUNCTION
350 ": bogus daemon response, type %d",
352 g_assert_not_reached ();
355 _wapi_shared_data->handles[idx].ref++;
358 g_message (G_GNUC_PRETTY_FUNCTION ": handle %p ref now %d",
359 handle, _wapi_shared_data->handles[idx].ref);
364 void _wapi_handle_unref (gpointer handle)
366 guint32 idx=GPOINTER_TO_UINT (handle);
370 WapiHandleRequest req;
371 WapiHandleResponse resp;
373 req.type=WapiHandleRequestType_Close;
374 req.u.close.handle=GPOINTER_TO_UINT (handle);
376 _wapi_daemon_request_response (daemon_sock, &req, &resp);
377 if(resp.type!=WapiHandleResponseType_Close) {
378 g_warning (G_GNUC_PRETTY_FUNCTION
379 ": bogus daemon response, type %d",
381 g_assert_not_reached ();
383 destroy=resp.u.close.destroy;
386 _wapi_shared_data->handles[idx].ref--;
389 g_message (G_GNUC_PRETTY_FUNCTION ": handle %p ref now %d",
390 handle, _wapi_shared_data->handles[idx].ref);
393 /* Possible race condition here if another thread refs
394 * the handle between here and setting the type to
395 * UNUSED. I could lock a mutex, but I'm not sure
396 * that allowing a handle reference to reach 0 isn't
397 * an application bug anyway.
399 destroy=(_wapi_shared_data->handles[idx].ref==0);
404 g_message (G_GNUC_PRETTY_FUNCTION ": Destroying handle %p",
409 _wapi_handle_ops_close_shared (handle);
410 _wapi_shared_data->handles[idx].type=WAPI_HANDLE_UNUSED;
411 mono_mutex_destroy (&_wapi_shared_data->handles[idx].signal_mutex);
412 pthread_cond_destroy (&_wapi_shared_data->handles[idx].signal_cond);
413 memset (&_wapi_shared_data->handles[idx].u, '\0', sizeof(_wapi_shared_data->handles[idx].u));
416 _wapi_handle_ops_close_private (handle);
420 #define HDRSIZE sizeof(struct _WapiScratchHeader)
423 * _wapi_handle_scratch_store_internal:
424 * @bytes: Allocate no. bytes
426 * Like malloc(3) except its for the shared memory segment's scratch
427 * part. Memory block returned is zeroed out.
429 guint32 _wapi_handle_scratch_store_internal (guint32 bytes)
431 guint32 idx=0, last_idx=0;
432 struct _WapiScratchHeader *hdr, *last_hdr;
433 gboolean last_was_free=FALSE;
434 guchar *storage=&_wapi_shared_data->scratch_base[0];
437 g_message (G_GNUC_PRETTY_FUNCTION
438 ": looking for %d bytes of scratch space (%d bytes total)",
439 bytes, _WAPI_SHM_SCRATCH_SIZE);
442 hdr=(struct _WapiScratchHeader *)&storage[0];
443 if(hdr->flags==0 && hdr->length==0) {
444 /* Need to initialise scratch data */
445 hdr->flags |= WAPI_SHM_SCRATCH_FREE;
446 hdr->length = _WAPI_SHM_SCRATCH_SIZE - HDRSIZE;
449 while(idx< _WAPI_SHM_SCRATCH_SIZE) {
450 hdr=(struct _WapiScratchHeader *)&storage[idx];
452 /* Do a simple first-fit allocation, coalescing
453 * adjacent free blocks as we progress through the
456 if(hdr->flags & WAPI_SHM_SCRATCH_FREE &&
457 hdr->length >= bytes + HDRSIZE) {
459 guint32 old_length=hdr->length;
461 g_message (G_GNUC_PRETTY_FUNCTION ": found suitable free size at %d, length %d", idx, hdr->length);
464 hdr->flags &= ~WAPI_SHM_SCRATCH_FREE;
468 /* Put a new header in at the end of the used
471 hdr=(struct _WapiScratchHeader *)&storage[idx+bytes];
472 hdr->flags |= WAPI_SHM_SCRATCH_FREE;
473 hdr->length = old_length-bytes-HDRSIZE;
476 g_message (G_GNUC_PRETTY_FUNCTION ": new header at %d, length %d", idx+bytes, hdr->length);
480 * It was memset(0..) when free/made so no need to do it here
484 } else if(hdr->flags & WAPI_SHM_SCRATCH_FREE &&
485 last_was_free == FALSE) {
487 g_message (G_GNUC_PRETTY_FUNCTION ": found too-small free block at %d, length %d (previous used)", idx, hdr->length);
490 /* save this point in case we can coalesce it with
491 * the next block, if that is free.
496 idx+=(hdr->length+HDRSIZE);
497 } else if (hdr->flags & WAPI_SHM_SCRATCH_FREE &&
498 last_was_free == TRUE) {
500 g_message (G_GNUC_PRETTY_FUNCTION ": found too-small free block at %d, length %d (previous free)", idx, hdr->length);
503 /* This block and the previous are both free,
506 last_hdr->length += (hdr->length + HDRSIZE);
508 /* If the new block is now big enough, use it
509 * (next time round the loop)
511 if(last_hdr->length >= bytes + HDRSIZE) {
514 /* leave the last free info as it is,
515 * in case the next block is also free
516 * and can be coalesced too
518 idx=last_idx+last_hdr->length+HDRSIZE;
522 g_message (G_GNUC_PRETTY_FUNCTION
523 ": found used block at %d, length %d", idx,
527 /* must be used, try next chunk */
528 idx+=(hdr->length+HDRSIZE);
530 /* Don't let the coalescing blow away this block */
538 guint32 _wapi_handle_scratch_store (gconstpointer data, guint32 bytes)
540 static pthread_mutex_t scratch_mutex=PTHREAD_MUTEX_INITIALIZER;
543 /* No point storing no data */
549 WapiHandleRequest scratch;
550 WapiHandleResponse scratch_resp;
552 scratch.type=WapiHandleRequestType_Scratch;
553 scratch.u.scratch.length=bytes;
555 _wapi_daemon_request_response (daemon_sock, &scratch,
558 if(scratch_resp.type==WapiHandleResponseType_Scratch) {
559 idx=scratch_resp.u.scratch.idx;
561 g_warning (G_GNUC_PRETTY_FUNCTION
562 ": bogus daemon response, type %d",
564 g_assert_not_reached ();
567 pthread_mutex_lock (&scratch_mutex);
568 idx=_wapi_handle_scratch_store_internal (bytes);
569 pthread_mutex_unlock (&scratch_mutex);
572 /* Failed to allocate space */
577 memcpy (&_wapi_shared_data->scratch_base[idx], data, bytes);
582 guchar *_wapi_handle_scratch_lookup_as_string (guint32 idx)
584 struct _WapiScratchHeader *hdr;
586 guchar *storage=&_wapi_shared_data->scratch_base[0];
588 if(idx < HDRSIZE || idx > _WAPI_SHM_SCRATCH_SIZE) {
592 hdr=(struct _WapiScratchHeader *)&storage[idx - HDRSIZE];
593 str=g_malloc0 (hdr->length+1);
594 memcpy (str, &storage[idx], hdr->length);
600 * _wapi_handle_scratch_delete_internal:
601 * @idx: Index to free block
603 * Like free(3) except its for the shared memory segment's scratch
606 void _wapi_handle_scratch_delete_internal (guint32 idx)
608 struct _WapiScratchHeader *hdr;
609 guchar *storage=&_wapi_shared_data->scratch_base[0];
611 if(idx < HDRSIZE || idx > _WAPI_SHM_SCRATCH_SIZE) {
615 hdr=(struct _WapiScratchHeader *)&storage[idx - HDRSIZE];
616 memset (&storage[idx], '\0', hdr->length);
617 hdr->flags |= WAPI_SHM_SCRATCH_FREE;
619 /* We could coalesce forwards here if the next block is also
620 * free, but the _store() function will do that anyway.
624 void _wapi_handle_scratch_delete (guint32 idx)
627 WapiHandleRequest scratch_free;
628 WapiHandleResponse scratch_free_resp;
630 scratch_free.type=WapiHandleRequestType_ScratchFree;
631 scratch_free.u.scratch_free.idx=idx;
633 _wapi_daemon_request_response (daemon_sock, &scratch_free,
636 if(scratch_free_resp.type!=WapiHandleResponseType_ScratchFree) {
637 g_warning (G_GNUC_PRETTY_FUNCTION
638 ": bogus daemon response, type %d",
639 scratch_free_resp.type);
640 g_assert_not_reached ();
643 _wapi_handle_scratch_delete_internal (idx);
647 void _wapi_handle_register_capabilities (WapiHandleType type,
648 WapiHandleCapability caps)
650 handle_caps[type]=caps;
653 gboolean _wapi_handle_test_capabilities (gpointer handle,
654 WapiHandleCapability caps)
656 guint32 idx=GPOINTER_TO_UINT (handle);
659 type=_wapi_shared_data->handles[idx].type;
662 g_message (G_GNUC_PRETTY_FUNCTION ": testing 0x%x against 0x%x (%d)",
663 handle_caps[type], caps, handle_caps[type] & caps);
666 return((handle_caps[type] & caps)!=0);
669 void _wapi_handle_ops_close_shared (gpointer handle)
671 guint32 idx=GPOINTER_TO_UINT (handle);
674 type=_wapi_shared_data->handles[idx].type;
676 if(handle_ops[type]!=NULL && handle_ops[type]->close_shared!=NULL) {
677 handle_ops[type]->close_shared (handle);
681 void _wapi_handle_ops_close_private (gpointer handle)
683 guint32 idx=GPOINTER_TO_UINT (handle);
686 type=_wapi_shared_data->handles[idx].type;
688 if(handle_ops[type]!=NULL && handle_ops[type]->close_private!=NULL) {
689 handle_ops[type]->close_private (handle);
693 void _wapi_handle_ops_signal (gpointer handle)
695 guint32 idx=GPOINTER_TO_UINT (handle);
698 type=_wapi_shared_data->handles[idx].type;
700 if(handle_ops[type]!=NULL && handle_ops[type]->signal!=NULL) {
701 handle_ops[type]->signal (handle);
705 void _wapi_handle_ops_own (gpointer handle)
707 guint32 idx=GPOINTER_TO_UINT (handle);
710 type=_wapi_shared_data->handles[idx].type;
712 if(handle_ops[type]!=NULL && handle_ops[type]->own_handle!=NULL) {
713 handle_ops[type]->own_handle (handle);
717 gboolean _wapi_handle_ops_isowned (gpointer handle)
719 guint32 idx=GPOINTER_TO_UINT (handle);
722 type=_wapi_shared_data->handles[idx].type;
724 if(handle_ops[type]!=NULL && handle_ops[type]->is_owned!=NULL) {
725 return(handle_ops[type]->is_owned (handle));
733 * @handle: The handle to release
735 * Closes and invalidates @handle, releasing any resources it
736 * consumes. When the last handle to a temporary or non-persistent
737 * object is closed, that object can be deleted. Closing the same
738 * handle twice is an error.
740 * Return value: %TRUE on success, %FALSE otherwise.
742 gboolean CloseHandle(gpointer handle)
744 _wapi_handle_unref (handle);
749 gboolean _wapi_handle_count_signalled_handles (guint32 numhandles,
755 guint32 count, i, iter=0;
758 /* Lock all the handles, with backoff */
760 for(i=0; i<numhandles; i++) {
761 guint32 idx=GPOINTER_TO_UINT (handles[i]);
764 g_message (G_GNUC_PRETTY_FUNCTION ": attempting to lock %p",
768 ret=mono_mutex_trylock (&_wapi_shared_data->handles[idx].signal_mutex);
771 struct timespec sleepytime;
774 g_message (G_GNUC_PRETTY_FUNCTION ": attempt failed for %p", handles[i]);
778 idx=GPOINTER_TO_UINT (handles[i]);
779 mono_mutex_unlock (&_wapi_shared_data->handles[idx].signal_mutex);
782 /* If iter ever reaches 100 the nanosleep will
783 * return EINVAL immediately, but we have a
784 * design flaw if that happens.
788 g_warning (G_GNUC_PRETTY_FUNCTION
789 ": iteration overflow!");
794 sleepytime.tv_nsec=10000000 * iter; /* 10ms*iter */
797 g_message (G_GNUC_PRETTY_FUNCTION
798 ": Backing off for %d ms", iter*10);
800 nanosleep (&sleepytime, NULL);
807 g_message (G_GNUC_PRETTY_FUNCTION ": Locked all handles");
813 for(i=0; i<numhandles; i++) {
814 guint32 idx=GPOINTER_TO_UINT (handles[i]);
817 g_message (G_GNUC_PRETTY_FUNCTION ": Checking handle %p",
821 if(((_wapi_handle_test_capabilities (handles[i], WAPI_HANDLE_CAP_OWN)==TRUE) &&
822 (_wapi_handle_ops_isowned (handles[i])==TRUE)) ||
823 (_wapi_shared_data->handles[idx].signalled==TRUE)) {
827 g_message (G_GNUC_PRETTY_FUNCTION
828 ": Handle %p signalled", handles[i]);
837 g_message (G_GNUC_PRETTY_FUNCTION ": %d event handles signalled",
841 if((waitall==TRUE && count==numhandles) ||
842 (waitall==FALSE && count>0)) {
849 g_message (G_GNUC_PRETTY_FUNCTION ": Returning %d", ret);
857 void _wapi_handle_unlock_handles (guint32 numhandles, gpointer *handles)
861 for(i=0; i<numhandles; i++) {
862 guint32 idx=GPOINTER_TO_UINT (handles[i]);
865 g_message (G_GNUC_PRETTY_FUNCTION ": unlocking handle %p",
869 mono_mutex_unlock (&_wapi_shared_data->handles[idx].signal_mutex);
873 /* Process-shared handles (currently only process and thread handles
874 * are allowed, and they only work because once signalled they can't
875 * become unsignalled) are waited for by one process and signalled by
876 * another. Without process-shared conditions, the waiting process
877 * will block forever. To get around this, the four handle waiting
878 * functions use a short timeout when _POSIX_THREAD_PROCESS_SHARED is
879 * not available. They also return "success" if the fake timeout
880 * expired, and let the caller check signal status.
882 int _wapi_handle_wait_signal (void)
884 #ifdef _POSIX_THREAD_PROCESS_SHARED
885 return(mono_cond_wait (&_wapi_shared_data->signal_cond,
886 &_wapi_shared_data->signal_mutex));
888 struct timespec fake_timeout;
891 _wapi_calc_timeout (&fake_timeout, 100);
893 ret=mono_cond_timedwait (&_wapi_private_data->signal_cond,
894 &_wapi_private_data->signal_mutex,
901 #endif /* _POSIX_THREAD_PROCESS_SHARED */
904 int _wapi_handle_timedwait_signal (struct timespec *timeout)
906 #ifdef _POSIX_THREAD_PROCESS_SHARED
907 return(mono_cond_timedwait (&_wapi_shared_data->signal_cond,
908 &_wapi_shared_data->signal_mutex,
911 struct timespec fake_timeout;
914 _wapi_calc_timeout (&fake_timeout, 100);
916 if((fake_timeout.tv_sec>timeout->tv_sec) ||
917 (fake_timeout.tv_sec==timeout->tv_sec &&
918 fake_timeout.tv_nsec > timeout->tv_nsec)) {
919 /* Real timeout is less than 100ms time */
920 ret=mono_cond_timedwait (&_wapi_private_data->signal_cond,
921 &_wapi_private_data->signal_mutex,
924 ret=mono_cond_timedwait (&_wapi_private_data->signal_cond,
925 &_wapi_private_data->signal_mutex,
933 #endif /* _POSIX_THREAD_PROCESS_SHARED */
936 int _wapi_handle_wait_signal_handle (gpointer handle)
938 #ifdef _POSIX_THREAD_PROCESS_SHARED
939 guint32 idx=GPOINTER_TO_UINT (handle);
941 return(mono_cond_wait (&_wapi_shared_data->handles[idx].signal_cond,
942 &_wapi_shared_data->handles[idx].signal_mutex));
944 guint32 idx=GPOINTER_TO_UINT (handle);
945 struct timespec fake_timeout;
948 _wapi_calc_timeout (&fake_timeout, 100);
950 ret=mono_cond_timedwait (&_wapi_shared_data->handles[idx].signal_cond,
951 &_wapi_shared_data->handles[idx].signal_mutex,
958 #endif /* _POSIX_THREAD_PROCESS_SHARED */
961 int _wapi_handle_timedwait_signal_handle (gpointer handle,
962 struct timespec *timeout)
964 #ifdef _POSIX_THREAD_PROCESS_SHARED
965 guint32 idx=GPOINTER_TO_UINT (handle);
967 return(mono_cond_timedwait (&_wapi_shared_data->handles[idx].signal_cond,
968 &_wapi_shared_data->handles[idx].signal_mutex,
971 guint32 idx=GPOINTER_TO_UINT (handle);
972 struct timespec fake_timeout;
975 _wapi_calc_timeout (&fake_timeout, 100);
977 if((fake_timeout.tv_sec>timeout->tv_sec) ||
978 (fake_timeout.tv_sec==timeout->tv_sec &&
979 fake_timeout.tv_nsec > timeout->tv_nsec)) {
980 /* Real timeout is less than 100ms time */
981 ret=mono_cond_timedwait (&_wapi_shared_data->handles[idx].signal_cond,
982 &_wapi_shared_data->handles[idx].signal_mutex,
985 ret=mono_cond_timedwait (&_wapi_shared_data->handles[idx].signal_cond,
986 &_wapi_shared_data->handles[idx].signal_mutex,
994 #endif /* _POSIX_THREAD_PROCESS_SHARED */
997 gboolean _wapi_handle_process_fork (guint32 cmd, guint32 args, guint32 env,
998 guint32 dir, gboolean inherit,
999 guint32 flags, gpointer stdin_handle,
1000 gpointer stdout_handle,
1001 gpointer stderr_handle,
1002 gpointer *process_handle,
1003 gpointer *thread_handle, guint32 *pid,
1006 WapiHandleRequest fork_proc;
1007 WapiHandleResponse fork_proc_resp;
1008 int in_fd, out_fd, err_fd;
1014 fork_proc.type=WapiHandleRequestType_ProcessFork;
1015 fork_proc.u.process_fork.cmd=cmd;
1016 fork_proc.u.process_fork.args=args;
1017 fork_proc.u.process_fork.env=env;
1018 fork_proc.u.process_fork.dir=dir;
1019 fork_proc.u.process_fork.stdin_handle=GPOINTER_TO_UINT (stdin_handle);
1020 fork_proc.u.process_fork.stdout_handle=GPOINTER_TO_UINT (stdout_handle);
1021 fork_proc.u.process_fork.stderr_handle=GPOINTER_TO_UINT (stderr_handle);
1022 fork_proc.u.process_fork.inherit=inherit;
1023 fork_proc.u.process_fork.flags=flags;
1025 in_fd=_wapi_file_handle_to_fd (stdin_handle);
1026 out_fd=_wapi_file_handle_to_fd (stdout_handle);
1027 err_fd=_wapi_file_handle_to_fd (stderr_handle);
1029 if(in_fd==-1 || out_fd==-1 || err_fd==-1) {
1030 /* We were given duff handles */
1031 /* FIXME: error code */
1035 _wapi_daemon_request_response_with_fds (daemon_sock, &fork_proc,
1036 &fork_proc_resp, in_fd,
1038 if(fork_proc_resp.type==WapiHandleResponseType_ProcessFork) {
1039 *process_handle=GUINT_TO_POINTER (fork_proc_resp.u.process_fork.process_handle);
1040 *thread_handle=GUINT_TO_POINTER (fork_proc_resp.u.process_fork.thread_handle);
1041 *pid=fork_proc_resp.u.process_fork.pid;
1042 *tid=fork_proc_resp.u.process_fork.tid;
1044 /* If there was an internal error, the handles will be
1045 * 0. If there was an error forking or execing, the
1046 * handles will have values, and process_handle's
1047 * exec_errno will be set, and the handle will be
1048 * signalled immediately.
1050 if(process_handle==0 || thread_handle==0) {
1056 g_warning (G_GNUC_PRETTY_FUNCTION
1057 ": bogus daemon response, type %d",
1058 fork_proc_resp.type);
1059 g_assert_not_reached ();