2 * daemon.c: The handle daemon
5 * Dick Porter (dick@ximian.com)
7 * (C) 2002 Ximian, Inc.
14 #include <sys/types.h>
15 #include <sys/socket.h>
29 #include <mono/io-layer/io-layer.h>
30 #include <mono/io-layer/handles-private.h>
31 #include <mono/io-layer/wapi-private.h>
32 #include <mono/io-layer/daemon-messages.h>
33 #include <mono/io-layer/timefuncs-private.h>
34 #include <mono/io-layer/daemon-private.h>
38 /* The shared thread codepath doesn't seem to work yet... */
39 #undef _POSIX_THREAD_PROCESS_SHARED
41 /* Keep track of the number of clients */
44 /* Arrays to keep track of channel data for the
45 * daemon and clients indexed by file descriptor
49 typedef struct _channel_data {
50 int io_source; /* the ID given back by g_io_add_watch */
51 guint32 *open_handles; /* array of open handles for this client */
54 static ChannelData *daemon_channel_data=NULL;
55 static ChannelData *channels=NULL;
56 static int channels_length=0;
58 /* The socket which we listen to new connections on */
61 /* Set to TRUE by the SIGCHLD signal handler */
62 static volatile gboolean check_processes=FALSE;
64 static gboolean fd_activity (GIOChannel *channel, GIOCondition condition,
68 /* Deletes the shared memory segment. If we're exiting on error,
69 * clients will get EPIPEs.
71 static void cleanup (void)
75 #ifdef NEED_LINK_UNLINK
76 unlink(_wapi_shared_data[0]->daemon);
78 for(i=1; i<_wapi_shared_data[0]->num_segments; i++) {
79 unlink (_wapi_shm_file (WAPI_SHM_DATA, i));
81 unlink (_wapi_shm_file (WAPI_SHM_DATA, 0));
83 /* There's only one scratch file */
84 unlink (_wapi_shm_file (WAPI_SHM_SCRATCH, 0));
87 /* If there is only one socket, and no child processes, we can exit.
88 * We test for child processes by counting handle references held by
91 static void maybe_exit (void)
96 g_message (G_GNUC_PRETTY_FUNCTION ": Seeing if we should exit");
101 g_message (G_GNUC_PRETTY_FUNCTION ": Still got clients");
106 /* Prevent new clients from connecting... */
107 _wapi_shared_data[0]->daemon_running=DAEMON_CLOSING;
110 i<_wapi_shared_data[0]->num_segments * _WAPI_HANDLES_PER_SEGMENT;
112 if(daemon_channel_data->open_handles[i]>0) {
114 g_message (G_GNUC_PRETTY_FUNCTION
115 ": Still got handle references");
118 _wapi_shared_data[0]->daemon_running=DAEMON_RUNNING;
124 /* Last check, make sure no client came along while we were
125 * checking the handle lists.
127 * Use poll() directly here, as glib doesn't seem to have any
128 * exposed way of seeing if a file descriptor is ready
129 * (g_io_channel_get_buffer_condition() isn't it.)
131 * Crappy systems that don't have poll() will just have to
132 * lump it (for them there is still the very slight chance
133 * that someone tried to connect just as the DAEMON_CLOSING
134 * flag was being set.)
137 struct pollfd fds[1];
140 fds[0].events=POLLIN;
144 g_message (G_GNUC_PRETTY_FUNCTION ": Last connect check");
147 if(poll (fds, 1, 0)>0) {
148 /* Someone did connect, so carry on running */
150 g_message (G_GNUC_PRETTY_FUNCTION
151 ": Someone connected");
154 _wapi_shared_data[0]->daemon_running=DAEMON_RUNNING;
161 g_message (G_GNUC_PRETTY_FUNCTION ": Byebye");
172 * Called if daemon receives a SIGTERM or SIGINT
174 static void signal_handler (int signo)
177 g_message (G_GNUC_PRETTY_FUNCTION ": daemon received signal %d", signo);
187 * Called if daemon receives a SIGCHLD, and notes that a process needs
188 * to be wait()ed for.
190 static void sigchld_handler (int unused)
192 /* Notice that a child process died */
193 check_processes=TRUE;
199 * Bind signals and attach to shared memory
201 static void startup (void)
205 sa.sa_handler=signal_handler;
206 sigemptyset (&sa.sa_mask);
208 sigaction (SIGINT, &sa, NULL);
209 sigaction (SIGTERM, &sa, NULL);
211 #ifndef HAVE_MSG_NOSIGNAL
212 sa.sa_handler=SIG_IGN;
213 sigaction (SIGPIPE, &sa, NULL);
216 sa.sa_handler=sigchld_handler;
217 sa.sa_flags=SA_NOCLDSTOP;
218 sigaction (SIGCHLD, &sa, NULL);
220 #ifdef NEED_LINK_UNLINK
221 /* Here's a more portable method... */
222 snprintf (_wapi_shared_data[0]->daemon, MONO_SIZEOF_SUNPATH-1,
223 "/tmp/mono-handle-daemon-%d-%ld-%ld", getuid (), random (),
226 /* Leave the first byte NULL so we create the socket in the
227 * abstrace namespace, not on the filesystem. (Lets see how
228 * portable _that_ is :)
230 * The name is intended to be unique, not cryptographically
233 snprintf (_wapi_shared_data[0]->daemon+1, MONO_SIZEOF_SUNPATH-2,
234 "mono-handle-daemon-%d-%d-%ld", getuid (), getpid (),
242 * @channel_data: Channel data for calling client
243 * @handle: handle to inc refcnt
245 * Increase ref count of handle for the calling client. Handle 0 is
248 static void ref_handle (ChannelData *channel_data, guint32 handle)
250 guint32 segment, idx;
256 _wapi_handle_segment (GUINT_TO_POINTER (handle), &segment, &idx);
258 _wapi_shared_data[segment]->handles[idx].ref++;
259 channel_data->open_handles[handle]++;
262 g_message (G_GNUC_PRETTY_FUNCTION
263 ": handle 0x%x ref now %d (%d this process)", handle,
264 _wapi_shared_data[segment]->handles[idx].ref,
265 channel_data->open_handles[handle]);
271 * @channel_data: Channel data for calling client
272 * @handle: handle to inc refcnt
274 * Decrease ref count of handle for the calling client. If global ref
275 * count reaches 0 it is free'ed. Return TRUE if the local ref count
276 * is 0. Handle 0 is ignored.
278 static gboolean unref_handle (ChannelData *channel_data, guint32 handle)
280 gboolean destroy=FALSE;
281 guint32 segment, idx;
287 if (channel_data->open_handles[handle] == 0) {
288 g_warning(G_GNUC_PRETTY_FUNCTION
289 ": unref on %d called when ref was already 0",
294 _wapi_handle_segment (GUINT_TO_POINTER (handle), &segment, &idx);
296 _wapi_shared_data[segment]->handles[idx].ref--;
297 channel_data->open_handles[handle]--;
300 g_message (G_GNUC_PRETTY_FUNCTION
301 ": handle 0x%x ref now %d (%d this process)", handle,
302 _wapi_shared_data[segment]->handles[idx].ref,
303 channel_data->open_handles[handle]);
306 if(channel_data->open_handles[handle]==0) {
307 /* This client has released the handle */
311 if(_wapi_shared_data[segment]->handles[idx].ref==0) {
312 if (channel_data->open_handles[handle]!=0) {
313 g_warning (G_GNUC_PRETTY_FUNCTION ": per-process open_handles mismatch, set to %d, should be 0",
314 channel_data->open_handles[handle]);
318 g_message (G_GNUC_PRETTY_FUNCTION ": Destroying handle 0x%x",
322 _wapi_handle_ops_close_shared (GUINT_TO_POINTER (handle));
324 #if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
325 mono_mutex_destroy (&_wapi_shared_data[segment]->handles[idx].signal_mutex);
326 pthread_cond_destroy (&_wapi_shared_data[segment]->handles[idx].signal_cond);
329 memset (&_wapi_shared_data[segment]->handles[idx].u, '\0', sizeof(_wapi_shared_data[segment]->handles[idx].u));
330 _wapi_shared_data[segment]->handles[idx].type=WAPI_HANDLE_UNUSED;
333 if(channel_data == daemon_channel_data) {
334 /* The daemon released a reference, so see if it's
345 * @fd: Filehandle to add
347 * Create a new GIOChannel, and add it to the main loop event sources.
349 static void add_fd(int fd)
351 GIOChannel *io_channel;
354 io_channel=g_io_channel_unix_new (fd);
356 /* Turn off all encoding and buffering crap */
357 g_io_channel_set_encoding (io_channel, NULL, NULL);
358 g_io_channel_set_buffered (io_channel, FALSE);
360 refs=g_new0 (guint32,_wapi_shared_data[0]->num_segments * _WAPI_HANDLES_PER_SEGMENT);
362 if(fd>=channels_length) {
363 /* Add a bit of padding, so we dont resize for _every_
366 int old_len=channels_length * sizeof(ChannelData);
368 channels_length=fd+10;
370 channels=g_new0 (ChannelData, channels_length);
371 /* We rely on the daemon channel being created first.
372 * That's safe, because every other channel is the
373 * result of an accept() on the daemon channel.
375 daemon_channel_data = &channels[fd];
377 int daemon_index=daemon_channel_data - channels;
379 /* Can't use g_renew here, because the unused
380 * elements must be NULL and g_renew doesn't
381 * initialise the memory it returns
383 channels=_wapi_g_renew0 (channels, old_len, channels_length * sizeof(ChannelData));
384 daemon_channel_data = channels + daemon_index;
389 channels[fd].open_handles=refs;
390 channels[fd].io_source=g_io_add_watch (io_channel, G_IO_IN|G_IO_ERR|G_IO_HUP|G_IO_NVAL,
398 * @channel: GIOChannel to close
400 * Closes the IO channel. Closes all handles that it may have open. If
401 * only main_sock is left, the daemon is shut down.
403 static void rem_fd(GIOChannel *channel, ChannelData *channel_data)
405 guint32 handle_count;
408 fd=g_io_channel_unix_get_fd (channel);
410 if(fd == main_sock) {
411 /* We shouldn't be deleting the daemon's fd */
412 g_warning (G_GNUC_PRETTY_FUNCTION ": Deleting daemon fd!");
418 g_message (G_GNUC_PRETTY_FUNCTION ": Removing client fd %d", fd);
421 g_io_channel_shutdown (channel, TRUE, NULL);
422 g_source_remove (channel_data->io_source);
423 g_io_channel_unref (channel);
426 i<_wapi_shared_data[0]->num_segments * _WAPI_HANDLES_PER_SEGMENT;
428 handle_count=channel_data->open_handles[i];
430 for(j=0; j<handle_count; j++) {
432 g_message (G_GNUC_PRETTY_FUNCTION ": closing handle 0x%x for client at index %d", i, g_io_channel_unix_get_fd (channel));
434 /* Ignore the hint to the client to destroy
435 * the handle private data
437 unref_handle (channel_data, i);
441 g_free (channel_data->open_handles);
442 channel_data->open_handles=NULL;
443 channel_data->io_source=0;
447 /* Just the master socket left, so see if we can
454 static gboolean process_compare (gpointer handle, gpointer user_data)
456 struct _WapiHandle_process *process_handle;
459 guint32 segment, idx;
461 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_PROCESS,
462 (gpointer *)&process_handle, NULL);
464 g_warning (G_GNUC_PRETTY_FUNCTION
465 ": error looking up process handle %p", handle);
469 _wapi_handle_segment (handle, &segment, &idx);
470 if (_wapi_shared_data[segment]->handles[idx].signalled) {
474 pid=GPOINTER_TO_UINT (user_data);
475 if(process_handle->id==pid) {
482 static gboolean process_thread_compare (gpointer handle, gpointer user_data)
484 struct _WapiHandle_thread *thread_handle;
486 guint32 segment, idx;
488 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
489 (gpointer *)&thread_handle, NULL);
491 g_warning (G_GNUC_PRETTY_FUNCTION
492 ": error looking up thread handle %p", handle);
496 if(thread_handle->process_handle==user_data) {
497 /* Signal the handle. Don't use
498 * _wapi_handle_set_signal_state() unless we have
499 * process-shared pthread support.
502 g_message (G_GNUC_PRETTY_FUNCTION ": Set thread handle %p signalled, because its process died", handle);
505 thread_handle->exitstatus=0;
507 #if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
508 _wapi_handle_lock_handle (handle);
509 _wapi_handle_set_signal_state (handle, TRUE, TRUE);
510 _wapi_handle_unlock_handle (handle);
512 /* Just tweak the signal state directly. This is not
513 * recommended behaviour, but it works for threads
514 * because they can never become unsignalled. There
515 * are some nasty kludges in the handle waiting code
516 * to cope with missing condition signals for when
517 * process-shared pthread support is missing.
519 _wapi_handle_segment (handle, &segment, &idx);
520 _wapi_shared_data[segment]->handles[idx].signalled=TRUE;
521 #endif /* _POSIX_THREAD_PROCESS_SHARED */
524 /* Return false to keep searching */
528 /* Find the handle associated with pid, mark it dead and record exit
529 * status. Finds all thread handles associated with this process
530 * handle, and marks those signalled too, with exitstatus '0'. It
531 * also drops the daemon's reference to the handle, and the thread
532 * pointed at by main_thread.
534 static void process_post_mortem (pid_t pid, int status)
536 gpointer process_handle;
537 struct _WapiHandle_process *process_handle_data;
538 guint32 segment, idx;
540 process_handle=_wapi_search_handle (WAPI_HANDLE_PROCESS,
542 GUINT_TO_POINTER (pid),
543 (gpointer *)&process_handle_data,
545 if(process_handle==0) {
546 g_warning (G_GNUC_PRETTY_FUNCTION
547 ": Couldn't find handle for process %d!", pid);
549 /* Signal the handle. Don't use
550 * _wapi_handle_set_signal_state() unless we have
551 * process-shared pthread support.
556 g_message (G_GNUC_PRETTY_FUNCTION
557 ": Set process %d exitstatus to %d", pid,
558 WEXITSTATUS (status));
561 /* Technically WEXITSTATUS is only valid if the
562 * process exited normally, but I don't care if the
563 * process caught a signal or not.
565 process_handle_data->exitstatus=WEXITSTATUS (status);
568 gettimeofday (&tv, NULL);
569 _wapi_timeval_to_filetime (&tv,
570 &process_handle_data->exit_time);
572 #if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
573 _wapi_handle_lock_handle (process_handle);
574 _wapi_handle_set_signal_state (process_handle, TRUE, TRUE);
575 _wapi_handle_unlock_handle (process_handle);
577 /* Just tweak the signal state directly. This is not
578 * recommended behaviour, but it works for processes
579 * because they can never become unsignalled. There
580 * are some nasty kludges in the handle waiting code
581 * to cope with missing condition signals for when
582 * process-shared pthread support is missing.
584 _wapi_handle_segment (process_handle, &segment, &idx);
585 _wapi_shared_data[segment]->handles[idx].signalled=TRUE;
586 #endif /* _POSIX_THREAD_PROCESS_SHARED */
589 /* Find all threads that have their process
590 * handle==process_handle. Ignore the return value, all the
591 * work will be done in the compare func
593 (void)_wapi_search_handle (WAPI_HANDLE_THREAD, process_thread_compare,
594 process_handle, NULL, NULL);
596 unref_handle (daemon_channel_data,
597 GPOINTER_TO_UINT (process_handle_data->main_thread));
598 unref_handle (daemon_channel_data, GPOINTER_TO_UINT (process_handle));
601 static void process_died (void)
606 check_processes=FALSE;
609 g_message (G_GNUC_PRETTY_FUNCTION ": Reaping processes");
613 pid=waitpid (-1, &status, WNOHANG);
614 if(pid==0 || pid==-1) {
615 /* Finished waiting. I was checking pid==-1
616 * separately but was getting ECHILD when
617 * there were no more child processes (which
618 * doesnt seem to conform to the man page)
622 /* pid contains the ID of a dead process */
624 g_message (G_GNUC_PRETTY_FUNCTION ": process %d reaped", pid);
626 process_post_mortem (pid, status);
634 * @channel: channel to send reply to
635 * @resp: Package to send
637 * Send a package to a client
639 static void send_reply (GIOChannel *channel, WapiHandleResponse *resp)
642 _wapi_daemon_response (g_io_channel_unix_get_fd (channel), resp);
647 * @channel: The client making the request
648 * @channel_data: Our data for this channel
649 * @type: type to init handle to
651 * Find a free handle and initialize it to 'type', increase refcnt and
652 * send back a reply to the client.
654 static void process_new (GIOChannel *channel, ChannelData *channel_data,
658 WapiHandleResponse resp={0};
660 handle=_wapi_handle_new_internal (type);
662 /* Try and allocate a new shared segment, and have
665 guint32 segment=_wapi_shared_data[0]->num_segments;
668 _wapi_handle_ensure_mapped (segment);
669 if(_wapi_shared_data[segment]!=NULL) {
670 /* Got a new segment */
671 gulong old_len, new_len;
673 old_len=_wapi_shared_data[0]->num_segments * _WAPI_HANDLES_PER_SEGMENT * sizeof(guint32);
674 _wapi_shared_data[0]->num_segments++;
675 new_len=_wapi_shared_data[0]->num_segments * _WAPI_HANDLES_PER_SEGMENT * sizeof(guint32);
677 /* Need to expand all the handle reference
681 for(i=0; i<channels_length; i++) {
682 if(channels[i].open_handles!=NULL) {
683 channels[i].open_handles=_wapi_g_renew0 (channels[i].open_handles, old_len, new_len);
687 handle=_wapi_handle_new_internal (type);
689 /* Map failed. Just return 0 meaning "out of
695 /* handle might still be set to 0. This is handled at the
699 ref_handle (channel_data, handle);
702 g_message (G_GNUC_PRETTY_FUNCTION ": returning new handle 0x%x",
706 resp.type=WapiHandleResponseType_New;
707 resp.u.new.type=type;
708 resp.u.new.handle=handle;
710 send_reply (channel, &resp);
715 * @channel: The client making the request
716 * @channel_data: Our data for this channel
717 * @handle: handle no.
719 * Increase refcnt on a previously created handle and send back a
720 * response to the client.
722 static void process_open (GIOChannel *channel, ChannelData *channel_data,
725 WapiHandleResponse resp={0};
726 guint32 segment, idx;
727 struct _WapiHandleShared *shared;
729 _wapi_handle_segment (GUINT_TO_POINTER (handle), &segment, &idx);
730 shared=&_wapi_shared_data[segment]->handles[idx];
732 if(shared->type!=WAPI_HANDLE_UNUSED && handle!=0) {
733 ref_handle (channel_data, handle);
736 g_message (G_GNUC_PRETTY_FUNCTION
737 ": returning new handle 0x%x", handle);
740 resp.type=WapiHandleResponseType_Open;
741 resp.u.new.type=shared->type;
742 resp.u.new.handle=handle;
744 send_reply (channel, &resp);
749 resp.type=WapiHandleResponseType_Open;
752 send_reply (channel, &resp);
757 * @channel: The client making the request
758 * @channel_data: Our data for this channel
759 * @handle: handle no.
761 * Decrease refcnt on a previously created handle and send back a
762 * response to the client with notice of it being destroyed.
764 static void process_close (GIOChannel *channel, ChannelData *channel_data,
767 WapiHandleResponse resp={0};
769 resp.type=WapiHandleResponseType_Close;
770 resp.u.close.destroy=unref_handle (channel_data, handle);
773 g_message (G_GNUC_PRETTY_FUNCTION ": unreffing handle 0x%x", handle);
776 send_reply (channel, &resp);
781 * @channel: The client making the request
782 * @length: allocate this much scratch space
784 * Allocate some scratch space and send a reply to the client.
786 static void process_scratch (GIOChannel *channel, guint32 length)
788 WapiHandleResponse resp={0};
790 resp.type=WapiHandleResponseType_Scratch;
791 resp.u.scratch.idx=_wapi_handle_scratch_store_internal (length, &resp.u.scratch.remap);
793 g_message (G_GNUC_PRETTY_FUNCTION ": allocating scratch index 0x%x",
797 send_reply (channel, &resp);
801 * process_scratch_free:
802 * @channel: The client making the request
803 * @scratch_idx: deallocate this scratch space
805 * Deallocate scratch space and send a reply to the client.
807 static void process_scratch_free (GIOChannel *channel, guint32 scratch_idx)
809 WapiHandleResponse resp={0};
811 resp.type=WapiHandleResponseType_ScratchFree;
812 _wapi_handle_scratch_delete_internal (scratch_idx);
815 g_message (G_GNUC_PRETTY_FUNCTION ": deleting scratch index 0x%x",
819 send_reply (channel, &resp);
823 * process_process_fork:
824 * @channel: The client making the request
825 * @open_handles: An array of handles referenced by this client
826 * @process_fork: Describes the process to fork
827 * @fds: stdin, stdout, and stderr for the new process
829 * Forks a new process, and returns the process and thread data to the
832 static void process_process_fork (GIOChannel *channel, ChannelData *channel_data,
833 WapiHandleRequest_ProcessFork process_fork,
836 WapiHandleResponse resp={0};
837 guint32 process_handle, thread_handle;
838 struct _WapiHandle_process *process_handle_data;
839 struct _WapiHandle_thread *thread_handle_data;
842 resp.type=WapiHandleResponseType_ProcessFork;
844 /* Create handles first, so the child process can store exec
845 * errors. Either handle might be set to 0, if this happens
846 * just reply to the client without bothering to fork. The
847 * client must check if either handle is 0 and take
848 * appropriate error handling action.
850 process_handle=_wapi_handle_new_internal (WAPI_HANDLE_PROCESS);
851 ref_handle (daemon_channel_data, process_handle);
852 ref_handle (channel_data, process_handle);
854 thread_handle=_wapi_handle_new_internal (WAPI_HANDLE_THREAD);
855 ref_handle (daemon_channel_data, thread_handle);
856 ref_handle (channel_data, thread_handle);
858 if(process_handle==0 || thread_handle==0) {
859 /* unref_handle() copes with the handle being 0 */
860 unref_handle (daemon_channel_data, process_handle);
861 unref_handle (channel_data, process_handle);
862 unref_handle (daemon_channel_data, thread_handle);
863 unref_handle (channel_data, thread_handle);
867 char *cmd=NULL, *dir=NULL, **argv, **env;
872 /* Get usable copies of the cmd, dir and env now
873 * rather than in the child process. This is to
874 * prevent the race condition where the parent can
875 * return the reply to the client, which then promptly
876 * deletes the scratch data before the new process
877 * gets to see it. Also explode argv here so we can
878 * use it to set the process name.
880 cmd=_wapi_handle_scratch_lookup (process_fork.cmd);
881 dir=_wapi_handle_scratch_lookup (process_fork.dir);
882 env=_wapi_handle_scratch_lookup_string_array (process_fork.env);
884 ret=g_shell_parse_argv (cmd, NULL, &argv, &gerr);
886 /* FIXME: Could do something with the
889 process_handle_data->exec_errno=gerr->code;
892 g_message (G_GNUC_PRETTY_FUNCTION ": forking");
895 _wapi_lookup_handle (GUINT_TO_POINTER (process_handle),
897 (gpointer *)&process_handle_data,
900 _wapi_lookup_handle (GUINT_TO_POINTER (thread_handle),
902 (gpointer *)&thread_handle_data,
905 /* Fork, exec cmd with args and optional env,
906 * and return the handles with pid and blank
911 process_handle_data->exec_errno=errno;
916 /* should we detach from the process
917 * group? We're already running
918 * without a controlling tty...
921 /* Connect stdin, stdout and stderr */
926 if(process_fork.inherit!=TRUE) {
927 /* FIXME: do something here */
930 /* Close all file descriptors */
931 for(i=3; i<getdtablesize (); i++) {
935 /* pass process and thread handle info
936 * to the child, so it doesn't have to
937 * do an expensive search over the
943 while(env[env_count]!=NULL) {
947 env=(char **)g_renew (char **, env, env_count+3);
949 env[env_count]=g_strdup_printf ("_WAPI_PROCESS_HANDLE=%d", process_handle);
950 env[env_count+1]=g_strdup_printf ("_WAPI_THREAD_HANDLE=%d", thread_handle);
951 env[env_count+2]=NULL;
955 g_message (G_GNUC_PRETTY_FUNCTION
956 ": exec()ing [%s] in dir [%s]",
960 while(argv[i]!=NULL) {
961 g_message ("arg %d: [%s]",
967 while(env[i]!=NULL) {
968 g_message ("env %d: [%s]",
976 if(chdir (dir)==-1) {
977 process_handle_data->exec_errno=errno;
982 execve (argv[0], argv, env);
985 process_handle_data->exec_errno=errno;
991 /* store process name, based on the last section of the cmd */
993 char *slash=strrchr (argv[0], '/');
996 process_handle_data->proc_name=_wapi_handle_scratch_store (slash+1, strlen (slash+1));
998 process_handle_data->proc_name=_wapi_handle_scratch_store (argv[0], strlen (argv[0]));
1002 /* These seem to be the defaults on w2k */
1003 process_handle_data->min_working_set=204800;
1004 process_handle_data->max_working_set=1413120;
1016 process_handle_data->id=pid;
1017 process_handle_data->main_thread=GUINT_TO_POINTER (thread_handle);
1019 gettimeofday (&tv, NULL);
1020 _wapi_timeval_to_filetime (&tv,
1021 &process_handle_data->create_time);
1023 /* FIXME: if env==0, inherit the env from the current
1026 process_handle_data->env=process_fork.env;
1028 thread_handle_data->process_handle=GUINT_TO_POINTER (process_handle);
1030 resp.u.process_fork.pid=pid;
1033 resp.u.process_fork.process_handle=process_handle;
1034 resp.u.process_fork.thread_handle=thread_handle;
1036 send_reply (channel, &resp);
1041 * @channel: The client to read the request from
1042 * @open_handles: An array of handles referenced by this client
1044 * Read a message (A WapiHandleRequest) from a client and dispatch
1045 * whatever it wants to the process_* calls.
1047 static void read_message (GIOChannel *channel, ChannelData *channel_data)
1049 WapiHandleRequest req;
1050 int fds[3]={0, 1, 2};
1052 gboolean has_fds=FALSE;
1055 ret=_wapi_daemon_request (g_io_channel_unix_get_fd (channel), &req,
1058 /* Other end went away */
1060 g_message ("Read 0 bytes on fd %d, closing it",
1061 g_io_channel_unix_get_fd (channel));
1063 rem_fd (channel, channel_data);
1068 g_message ("Process request %d", req.type);
1071 case WapiHandleRequestType_New:
1072 process_new (channel, channel_data, req.u.new.type);
1074 case WapiHandleRequestType_Open:
1076 g_assert(req.u.open.handle < _wapi_shared_data[0]->num_segments * _WAPI_HANDLES_PER_SEGMENT);
1078 process_open (channel, channel_data, req.u.open.handle);
1080 case WapiHandleRequestType_Close:
1082 g_assert(req.u.close.handle < _wapi_shared_data[0]->num_segments * _WAPI_HANDLES_PER_SEGMENT);
1084 process_close (channel, channel_data, req.u.close.handle);
1086 case WapiHandleRequestType_Scratch:
1087 process_scratch (channel, req.u.scratch.length);
1089 case WapiHandleRequestType_ScratchFree:
1090 process_scratch_free (channel, req.u.scratch_free.idx);
1092 case WapiHandleRequestType_ProcessFork:
1093 process_process_fork (channel, channel_data,
1094 req.u.process_fork, fds);
1096 case WapiHandleRequestType_Error:
1099 /* Catch bogus requests */
1100 /* FIXME: call rem_fd? */
1106 g_message (G_GNUC_PRETTY_FUNCTION ": closing %d", fds[0]);
1107 g_message (G_GNUC_PRETTY_FUNCTION ": closing %d", fds[1]);
1108 g_message (G_GNUC_PRETTY_FUNCTION ": closing %d", fds[2]);
1119 * @channel: The IO channel that is active
1120 * @condition: The condition that has been satisfied
1121 * @data: A pointer to an array of handles referenced by this client
1123 * The callback called by the main loop when there is activity on an
1126 static gboolean fd_activity (GIOChannel *channel, GIOCondition condition,
1129 int fd=g_io_channel_unix_get_fd (channel);
1130 ChannelData *channel_data=&channels[fd];
1132 if(condition & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
1134 g_message ("fd %d error", fd);
1137 rem_fd (channel, channel_data);
1141 if(condition & (G_IO_IN | G_IO_PRI)) {
1144 struct sockaddr addr;
1145 socklen_t addrlen=sizeof(struct sockaddr);
1147 newsock=accept (main_sock, &addr, &addrlen);
1149 g_critical ("accept error: %s",
1150 g_strerror (errno));
1156 g_message ("accept returning %d", newsock);
1162 g_message ("reading data on fd %d", fd);
1165 read_message (channel, channel_data);
1170 return(FALSE); /* remove source */
1174 * _wapi_daemon_main:
1176 * Open socket, create shared mem segment and begin listening for
1179 void _wapi_daemon_main(gpointer data, gpointer scratch)
1181 struct sockaddr_un main_socket_address;
1185 g_message ("Starting up...");
1188 _wapi_shared_data[0]=data;
1189 _wapi_shared_scratch=scratch;
1190 _wapi_shared_scratch->is_shared=TRUE;
1192 /* Note that we've got the starting segment already */
1193 _wapi_shared_data[0]->num_segments=1;
1194 _wapi_shm_mapped_segments=1;
1198 main_sock=socket(PF_UNIX, SOCK_STREAM, 0);
1200 main_socket_address.sun_family=AF_UNIX;
1201 memcpy(main_socket_address.sun_path, _wapi_shared_data[0]->daemon,
1202 MONO_SIZEOF_SUNPATH);
1204 ret=bind(main_sock, (struct sockaddr *)&main_socket_address,
1205 sizeof(struct sockaddr_un));
1207 g_critical ("bind failed: %s", g_strerror (errno));
1208 _wapi_shared_data[0]->daemon_running=DAEMON_DIED_AT_STARTUP;
1216 ret=listen(main_sock, 5);
1218 g_critical ("listen failed: %s", g_strerror (errno));
1219 _wapi_shared_data[0]->daemon_running=DAEMON_DIED_AT_STARTUP;
1224 g_message("listening");
1229 /* We're finished setting up, let everyone else know we're
1230 * ready. From now on, it's up to us to delete the shared
1231 * memory segment when appropriate.
1233 _wapi_shared_data[0]->daemon_running=DAEMON_RUNNING;
1236 if(check_processes==TRUE) {
1241 g_message ("polling");
1244 /* Block until something happens. We don't use
1245 * g_main_loop_run() because we rely on the SIGCHLD
1246 * signal interrupting poll() so we can reap child
1247 * processes as soon as they die, without burning cpu
1248 * time by polling the flag.
1250 g_main_context_iteration (g_main_context_default (), TRUE);