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>
35 #include <mono/io-layer/socket-wrappers.h>
39 /* The shared thread codepath doesn't seem to work yet... */
40 #undef _POSIX_THREAD_PROCESS_SHARED
42 /* Keep track of the number of clients */
45 /* Arrays to keep track of channel data for the
46 * daemon and clients indexed by file descriptor
50 typedef struct _channel_data {
51 int io_source; /* the ID given back by g_io_add_watch */
52 guint32 *open_handles; /* array of open handles for this client */
55 static ChannelData *daemon_channel_data=NULL;
56 static ChannelData *channels=NULL;
57 static int channels_length=0;
59 /* The socket which we listen to new connections on */
62 /* Set to TRUE by the SIGCHLD signal handler */
63 static volatile gboolean check_processes=FALSE;
65 static gboolean fd_activity (GIOChannel *channel, GIOCondition condition,
69 /* Deletes the shared memory segment. If we're exiting on error,
70 * clients will get EPIPEs.
72 static void cleanup (void)
76 #ifdef NEED_LINK_UNLINK
77 unlink(_wapi_shared_data[0]->daemon);
79 for(i=1; i<_wapi_shared_data[0]->num_segments; i++) {
80 unlink (_wapi_shm_file (WAPI_SHM_DATA, i));
82 unlink (_wapi_shm_file (WAPI_SHM_DATA, 0));
84 /* There's only one scratch file */
85 unlink (_wapi_shm_file (WAPI_SHM_SCRATCH, 0));
88 /* If there is only one socket, and no child processes, we can exit.
89 * We test for child processes by counting handle references held by
92 static void maybe_exit (void)
97 g_message (G_GNUC_PRETTY_FUNCTION ": Seeing if we should exit");
102 g_message (G_GNUC_PRETTY_FUNCTION ": Still got clients");
107 /* Prevent new clients from connecting... */
108 _wapi_shared_data[0]->daemon_running=DAEMON_CLOSING;
111 i<_wapi_shared_data[0]->num_segments * _WAPI_HANDLES_PER_SEGMENT;
113 if(daemon_channel_data->open_handles[i]>0) {
115 g_message (G_GNUC_PRETTY_FUNCTION
116 ": Still got handle references");
119 _wapi_shared_data[0]->daemon_running=DAEMON_RUNNING;
125 /* Last check, make sure no client came along while we were
126 * checking the handle lists.
128 * Use poll() directly here, as glib doesn't seem to have any
129 * exposed way of seeing if a file descriptor is ready
130 * (g_io_channel_get_buffer_condition() isn't it.)
132 * Crappy systems that don't have poll() will just have to
133 * lump it (for them there is still the very slight chance
134 * that someone tried to connect just as the DAEMON_CLOSING
135 * flag was being set.)
138 struct pollfd fds[1];
141 fds[0].events=POLLIN;
145 g_message (G_GNUC_PRETTY_FUNCTION ": Last connect check");
148 if(poll (fds, 1, 0)>0) {
149 /* Someone did connect, so carry on running */
151 g_message (G_GNUC_PRETTY_FUNCTION
152 ": Someone connected");
155 _wapi_shared_data[0]->daemon_running=DAEMON_RUNNING;
162 g_message (G_GNUC_PRETTY_FUNCTION ": Byebye");
173 * Called if daemon receives a SIGTERM or SIGINT
175 static void signal_handler (int signo)
178 g_message (G_GNUC_PRETTY_FUNCTION ": daemon received signal %d", signo);
188 * Called if daemon receives a SIGCHLD, and notes that a process needs
189 * to be wait()ed for.
191 static void sigchld_handler (int unused)
193 /* Notice that a child process died */
194 check_processes=TRUE;
200 * Bind signals and attach to shared memory
202 static void startup (void)
206 sa.sa_handler=signal_handler;
207 sigemptyset (&sa.sa_mask);
209 sigaction (SIGINT, &sa, NULL);
210 sigaction (SIGTERM, &sa, NULL);
212 #ifndef HAVE_MSG_NOSIGNAL
213 sa.sa_handler=SIG_IGN;
214 sigaction (SIGPIPE, &sa, NULL);
217 sa.sa_handler=sigchld_handler;
218 sa.sa_flags=SA_NOCLDSTOP;
219 sigaction (SIGCHLD, &sa, NULL);
221 #ifdef NEED_LINK_UNLINK
222 /* Here's a more portable method... */
223 snprintf (_wapi_shared_data[0]->daemon, MONO_SIZEOF_SUNPATH-1,
224 "/tmp/mono-handle-daemon-%d-%ld-%ld", getuid (), random (),
227 /* Leave the first byte NULL so we create the socket in the
228 * abstrace namespace, not on the filesystem. (Lets see how
229 * portable _that_ is :)
231 * The name is intended to be unique, not cryptographically
234 snprintf (_wapi_shared_data[0]->daemon+1, MONO_SIZEOF_SUNPATH-2,
235 "mono-handle-daemon-%d-%d-%ld", getuid (), getpid (),
243 * @channel_data: Channel data for calling client
244 * @handle: handle to inc refcnt
246 * Increase ref count of handle for the calling client. Handle 0 is
249 static void ref_handle (ChannelData *channel_data, guint32 handle)
251 guint32 segment, idx;
257 _wapi_handle_segment (GUINT_TO_POINTER (handle), &segment, &idx);
259 _wapi_shared_data[segment]->handles[idx].ref++;
260 channel_data->open_handles[handle]++;
263 g_message (G_GNUC_PRETTY_FUNCTION
264 ": handle 0x%x ref now %d (%d this process)", handle,
265 _wapi_shared_data[segment]->handles[idx].ref,
266 channel_data->open_handles[handle]);
272 * @channel_data: Channel data for calling client
273 * @handle: handle to inc refcnt
275 * Decrease ref count of handle for the calling client. If global ref
276 * count reaches 0 it is free'ed. Return TRUE if the local ref count
277 * is 0. Handle 0 is ignored.
279 static gboolean unref_handle (ChannelData *channel_data, guint32 handle)
281 gboolean destroy=FALSE;
282 guint32 segment, idx;
288 if (channel_data->open_handles[handle] == 0) {
289 g_warning(G_GNUC_PRETTY_FUNCTION
290 ": unref on %d called when ref was already 0",
295 _wapi_handle_segment (GUINT_TO_POINTER (handle), &segment, &idx);
297 _wapi_shared_data[segment]->handles[idx].ref--;
298 channel_data->open_handles[handle]--;
301 g_message (G_GNUC_PRETTY_FUNCTION
302 ": handle 0x%x ref now %d (%d this process)", handle,
303 _wapi_shared_data[segment]->handles[idx].ref,
304 channel_data->open_handles[handle]);
307 if(channel_data->open_handles[handle]==0) {
308 /* This client has released the handle */
312 if(_wapi_shared_data[segment]->handles[idx].ref==0) {
313 if (channel_data->open_handles[handle]!=0) {
314 g_warning (G_GNUC_PRETTY_FUNCTION ": per-process open_handles mismatch, set to %d, should be 0",
315 channel_data->open_handles[handle]);
319 g_message (G_GNUC_PRETTY_FUNCTION ": Destroying handle 0x%x",
323 _wapi_handle_ops_close_shared (GUINT_TO_POINTER (handle));
325 #if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
326 mono_mutex_destroy (&_wapi_shared_data[segment]->handles[idx].signal_mutex);
327 pthread_cond_destroy (&_wapi_shared_data[segment]->handles[idx].signal_cond);
330 memset (&_wapi_shared_data[segment]->handles[idx].u, '\0', sizeof(_wapi_shared_data[segment]->handles[idx].u));
331 _wapi_shared_data[segment]->handles[idx].type=WAPI_HANDLE_UNUSED;
334 if(channel_data == daemon_channel_data) {
335 /* The daemon released a reference, so see if it's
346 * @fd: Filehandle to add
348 * Create a new GIOChannel, and add it to the main loop event sources.
350 static void add_fd(int fd, GMainContext *context)
352 GIOChannel *io_channel;
356 io_channel=g_io_channel_unix_new (fd);
358 /* Turn off all encoding and buffering crap */
359 g_io_channel_set_encoding (io_channel, NULL, NULL);
360 g_io_channel_set_buffered (io_channel, FALSE);
362 refs=g_new0 (guint32,_wapi_shared_data[0]->num_segments * _WAPI_HANDLES_PER_SEGMENT);
364 if(fd>=channels_length) {
365 /* Add a bit of padding, so we dont resize for _every_
368 int old_len=channels_length * sizeof(ChannelData);
370 channels_length=fd+10;
372 channels=g_new0 (ChannelData, channels_length);
373 /* We rely on the daemon channel being created first.
374 * That's safe, because every other channel is the
375 * result of an accept() on the daemon channel.
377 daemon_channel_data = &channels[fd];
379 int daemon_index=daemon_channel_data - channels;
381 /* Can't use g_renew here, because the unused
382 * elements must be NULL and g_renew doesn't
383 * initialise the memory it returns
385 channels=_wapi_g_renew0 (channels, old_len, channels_length * sizeof(ChannelData));
386 daemon_channel_data = channels + daemon_index;
391 channels[fd].open_handles=refs;
393 source = g_io_create_watch (io_channel,
394 G_IO_IN|G_IO_ERR|G_IO_HUP|G_IO_NVAL);
395 g_source_set_callback (source, (GSourceFunc)fd_activity,
397 channels[fd].io_source=g_source_attach (source, context);
398 g_source_unref (source);
405 * @channel: GIOChannel to close
407 * Closes the IO channel. Closes all handles that it may have open. If
408 * only main_sock is left, the daemon is shut down.
410 static void rem_fd(GIOChannel *channel, ChannelData *channel_data)
412 guint32 handle_count;
415 fd=g_io_channel_unix_get_fd (channel);
417 if(fd == main_sock) {
418 /* We shouldn't be deleting the daemon's fd */
419 g_warning (G_GNUC_PRETTY_FUNCTION ": Deleting daemon fd!");
425 g_message (G_GNUC_PRETTY_FUNCTION ": Removing client fd %d", fd);
428 if (channel_data->io_source == 0) {
430 g_message (G_GNUC_PRETTY_FUNCTION ": channel already closed for fd %d", fd);
436 g_io_channel_shutdown (channel, TRUE, NULL);
437 g_source_remove (channel_data->io_source);
438 g_io_channel_unref (channel);
441 i<_wapi_shared_data[0]->num_segments * _WAPI_HANDLES_PER_SEGMENT;
443 handle_count=channel_data->open_handles[i];
445 for(j=0; j<handle_count; j++) {
447 g_message (G_GNUC_PRETTY_FUNCTION ": closing handle 0x%x for client at index %d", i, g_io_channel_unix_get_fd (channel));
449 /* Ignore the hint to the client to destroy
450 * the handle private data
452 unref_handle (channel_data, i);
456 g_free (channel_data->open_handles);
457 channel_data->open_handles=NULL;
458 channel_data->io_source=0;
462 /* Just the master socket left, so see if we can
469 static gboolean process_compare (gpointer handle, gpointer user_data)
471 struct _WapiHandle_process *process_handle;
474 guint32 segment, idx;
476 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_PROCESS,
477 (gpointer *)&process_handle, NULL);
479 g_warning (G_GNUC_PRETTY_FUNCTION
480 ": error looking up process handle %p", handle);
484 _wapi_handle_segment (handle, &segment, &idx);
485 if (_wapi_shared_data[segment]->handles[idx].signalled) {
489 pid=GPOINTER_TO_UINT (user_data);
490 if(process_handle->id==pid) {
497 static gboolean process_thread_compare (gpointer handle, gpointer user_data)
499 struct _WapiHandle_thread *thread_handle;
501 guint32 segment, idx;
503 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
504 (gpointer *)&thread_handle, NULL);
506 g_warning (G_GNUC_PRETTY_FUNCTION
507 ": error looking up thread handle %p", handle);
511 if(thread_handle->process_handle==user_data) {
512 /* Signal the handle. Don't use
513 * _wapi_handle_set_signal_state() unless we have
514 * process-shared pthread support.
517 g_message (G_GNUC_PRETTY_FUNCTION ": Set thread handle %p signalled, because its process died", handle);
520 thread_handle->exitstatus=0;
522 #if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
523 _wapi_handle_lock_handle (handle);
524 _wapi_handle_set_signal_state (handle, TRUE, TRUE);
525 _wapi_handle_unlock_handle (handle);
527 /* Just tweak the signal state directly. This is not
528 * recommended behaviour, but it works for threads
529 * because they can never become unsignalled. There
530 * are some nasty kludges in the handle waiting code
531 * to cope with missing condition signals for when
532 * process-shared pthread support is missing.
534 _wapi_handle_segment (handle, &segment, &idx);
535 _wapi_shared_data[segment]->handles[idx].signalled=TRUE;
536 #endif /* _POSIX_THREAD_PROCESS_SHARED */
539 /* Return false to keep searching */
543 /* Find the handle associated with pid, mark it dead and record exit
544 * status. Finds all thread handles associated with this process
545 * handle, and marks those signalled too, with exitstatus '0'. It
546 * also drops the daemon's reference to the handle, and the thread
547 * pointed at by main_thread.
549 static void process_post_mortem (pid_t pid, int status)
551 gpointer process_handle;
552 struct _WapiHandle_process *process_handle_data;
553 guint32 segment, idx;
555 process_handle=_wapi_search_handle (WAPI_HANDLE_PROCESS,
557 GUINT_TO_POINTER (pid),
558 (gpointer *)&process_handle_data,
560 if(process_handle==0) {
563 * This may happen if we use Process.EnableRaisingEvents +
564 * process.Exited event and the parent has finished.
566 g_warning (G_GNUC_PRETTY_FUNCTION
567 ": Couldn't find handle for process %d!", pid);
570 /* Signal the handle. Don't use
571 * _wapi_handle_set_signal_state() unless we have
572 * process-shared pthread support.
577 g_message (G_GNUC_PRETTY_FUNCTION
578 ": Set process %d exitstatus to %d", pid,
579 WEXITSTATUS (status));
582 /* If the child terminated due to the receipt of a signal,
583 * the exit status must be based on WTERMSIG, since WEXITSTATUS
584 * returns 0 in this case.
586 if (WIFSIGNALED(status))
587 process_handle_data->exitstatus=128 + WTERMSIG (status);
589 process_handle_data->exitstatus=WEXITSTATUS (status);
592 gettimeofday (&tv, NULL);
593 _wapi_timeval_to_filetime (&tv,
594 &process_handle_data->exit_time);
596 #if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
597 _wapi_handle_lock_handle (process_handle);
598 _wapi_handle_set_signal_state (process_handle, TRUE, TRUE);
599 _wapi_handle_unlock_handle (process_handle);
601 /* Just tweak the signal state directly. This is not
602 * recommended behaviour, but it works for processes
603 * because they can never become unsignalled. There
604 * are some nasty kludges in the handle waiting code
605 * to cope with missing condition signals for when
606 * process-shared pthread support is missing.
608 _wapi_handle_segment (process_handle, &segment, &idx);
609 _wapi_shared_data[segment]->handles[idx].signalled=TRUE;
610 #endif /* _POSIX_THREAD_PROCESS_SHARED */
613 /* Find all threads that have their process
614 * handle==process_handle. Ignore the return value, all the
615 * work will be done in the compare func
617 (void)_wapi_search_handle (WAPI_HANDLE_THREAD, process_thread_compare,
618 process_handle, NULL, NULL);
620 unref_handle (daemon_channel_data,
621 GPOINTER_TO_UINT (process_handle_data->main_thread));
622 unref_handle (daemon_channel_data, GPOINTER_TO_UINT (process_handle));
625 static void process_died (void)
630 check_processes=FALSE;
633 g_message (G_GNUC_PRETTY_FUNCTION ": Reaping processes");
637 pid=waitpid (-1, &status, WNOHANG);
638 if(pid==0 || pid==-1) {
639 /* Finished waiting. I was checking pid==-1
640 * separately but was getting ECHILD when
641 * there were no more child processes (which
642 * doesnt seem to conform to the man page)
646 /* pid contains the ID of a dead process */
648 g_message (G_GNUC_PRETTY_FUNCTION ": process %d reaped", pid);
650 process_post_mortem (pid, status);
658 * @channel: channel to send reply to
659 * @resp: Package to send
661 * Send a package to a client
663 static void send_reply (GIOChannel *channel, WapiHandleResponse *resp)
666 _wapi_daemon_response (g_io_channel_unix_get_fd (channel), resp);
671 * @channel: The client making the request
672 * @channel_data: Our data for this channel
673 * @type: type to init handle to
675 * Find a free handle and initialize it to 'type', increase refcnt and
676 * send back a reply to the client.
678 static void process_new (GIOChannel *channel, ChannelData *channel_data,
682 WapiHandleResponse resp={0};
684 handle=_wapi_handle_new_internal (type);
686 /* Try and allocate a new shared segment, and have
689 guint32 segment=_wapi_shared_data[0]->num_segments;
692 _wapi_handle_ensure_mapped (segment);
693 if(_wapi_shared_data[segment]!=NULL) {
694 /* Got a new segment */
695 gulong old_len, new_len;
697 old_len=_wapi_shared_data[0]->num_segments * _WAPI_HANDLES_PER_SEGMENT * sizeof(guint32);
698 _wapi_shared_data[0]->num_segments++;
699 new_len=_wapi_shared_data[0]->num_segments * _WAPI_HANDLES_PER_SEGMENT * sizeof(guint32);
701 /* Need to expand all the handle reference
705 for(i=0; i<channels_length; i++) {
706 if(channels[i].open_handles!=NULL) {
707 channels[i].open_handles=_wapi_g_renew0 (channels[i].open_handles, old_len, new_len);
711 handle=_wapi_handle_new_internal (type);
713 /* Map failed. Just return 0 meaning "out of
719 /* handle might still be set to 0. This is handled at the
723 ref_handle (channel_data, handle);
726 g_message (G_GNUC_PRETTY_FUNCTION ": returning new handle 0x%x",
730 resp.type=WapiHandleResponseType_New;
731 resp.u.new.type=type;
732 resp.u.new.handle=handle;
734 send_reply (channel, &resp);
739 * @channel: The client making the request
740 * @channel_data: Our data for this channel
741 * @handle: handle no.
743 * Increase refcnt on a previously created handle and send back a
744 * response to the client.
746 static void process_open (GIOChannel *channel, ChannelData *channel_data,
749 WapiHandleResponse resp={0};
750 guint32 segment, idx;
751 struct _WapiHandleShared *shared;
753 _wapi_handle_segment (GUINT_TO_POINTER (handle), &segment, &idx);
754 shared=&_wapi_shared_data[segment]->handles[idx];
756 if(shared->type!=WAPI_HANDLE_UNUSED && handle!=0) {
757 ref_handle (channel_data, handle);
760 g_message (G_GNUC_PRETTY_FUNCTION
761 ": returning new handle 0x%x", handle);
764 resp.type=WapiHandleResponseType_Open;
765 resp.u.new.type=shared->type;
766 resp.u.new.handle=handle;
768 send_reply (channel, &resp);
773 resp.type=WapiHandleResponseType_Open;
776 send_reply (channel, &resp);
781 * @channel: The client making the request
782 * @channel_data: Our data for this channel
783 * @handle: handle no.
785 * Decrease refcnt on a previously created handle and send back a
786 * response to the client with notice of it being destroyed.
788 static void process_close (GIOChannel *channel, ChannelData *channel_data,
791 WapiHandleResponse resp={0};
793 resp.type=WapiHandleResponseType_Close;
794 resp.u.close.destroy=unref_handle (channel_data, handle);
797 g_message (G_GNUC_PRETTY_FUNCTION ": unreffing handle 0x%x", handle);
800 send_reply (channel, &resp);
805 * @channel: The client making the request
806 * @length: allocate this much scratch space
808 * Allocate some scratch space and send a reply to the client.
810 static void process_scratch (GIOChannel *channel, guint32 length)
812 WapiHandleResponse resp={0};
814 resp.type=WapiHandleResponseType_Scratch;
815 resp.u.scratch.idx=_wapi_handle_scratch_store_internal (length, &resp.u.scratch.remap);
817 g_message (G_GNUC_PRETTY_FUNCTION ": allocating scratch index 0x%x",
821 send_reply (channel, &resp);
825 * process_scratch_free:
826 * @channel: The client making the request
827 * @scratch_idx: deallocate this scratch space
829 * Deallocate scratch space and send a reply to the client.
831 static void process_scratch_free (GIOChannel *channel, guint32 scratch_idx)
833 WapiHandleResponse resp={0};
835 resp.type=WapiHandleResponseType_ScratchFree;
836 _wapi_handle_scratch_delete_internal (scratch_idx);
839 g_message (G_GNUC_PRETTY_FUNCTION ": deleting scratch index 0x%x",
843 send_reply (channel, &resp);
847 * process_process_kill:
848 * @channel: The client making the request
849 * @process_kill: pid and signal to send to the pid.
851 * Sends the specified signal to the process.
854 process_process_kill (GIOChannel *channel,
855 WapiHandleRequest_ProcessKill process_kill)
857 WapiHandleResponse resp = {0};
859 resp.type = WapiHandleResponseType_ProcessKill;
862 g_message (G_GNUC_PRETTY_FUNCTION ": kill (%d, %d)",
863 process_kill.pid, process_kill.signo);
865 if (kill (process_kill.pid, process_kill.signo) == -1) {
866 resp.u.process_kill.err = errno;
868 g_message (G_GNUC_PRETTY_FUNCTION ": kill (%d, %d) failed: %d",
869 process_kill.pid, process_kill.signo, resp.u.process_kill.err);
873 send_reply (channel, &resp);
877 * process_process_fork:
878 * @channel: The client making the request
879 * @process_fork: Describes the process to fork
880 * @fds: stdin, stdout, and stderr for the new process
882 * Forks a new process, and returns the process and thread data to the
885 static void process_process_fork (GIOChannel *channel, ChannelData *channel_data,
886 WapiHandleRequest_ProcessFork process_fork,
889 WapiHandleResponse resp={0};
890 guint32 process_handle, thread_handle;
891 struct _WapiHandle_process *process_handle_data;
892 struct _WapiHandle_thread *thread_handle_data;
895 resp.type=WapiHandleResponseType_ProcessFork;
897 /* Create handles first, so the child process can store exec
898 * errors. Either handle might be set to 0, if this happens
899 * just reply to the client without bothering to fork. The
900 * client must check if either handle is 0 and take
901 * appropriate error handling action.
903 process_handle=_wapi_handle_new_internal (WAPI_HANDLE_PROCESS);
904 ref_handle (daemon_channel_data, process_handle);
905 ref_handle (channel_data, process_handle);
907 thread_handle=_wapi_handle_new_internal (WAPI_HANDLE_THREAD);
908 ref_handle (daemon_channel_data, thread_handle);
909 ref_handle (channel_data, thread_handle);
911 if(process_handle==0 || thread_handle==0) {
912 /* unref_handle() copes with the handle being 0 */
913 unref_handle (daemon_channel_data, process_handle);
914 unref_handle (channel_data, process_handle);
915 unref_handle (daemon_channel_data, thread_handle);
916 unref_handle (channel_data, thread_handle);
920 char *cmd=NULL, *dir=NULL, **argv, **env;
925 /* Get usable copies of the cmd, dir and env now
926 * rather than in the child process. This is to
927 * prevent the race condition where the parent can
928 * return the reply to the client, which then promptly
929 * deletes the scratch data before the new process
930 * gets to see it. Also explode argv here so we can
931 * use it to set the process name.
933 cmd=_wapi_handle_scratch_lookup (process_fork.cmd);
934 dir=_wapi_handle_scratch_lookup (process_fork.dir);
935 env=_wapi_handle_scratch_lookup_string_array (process_fork.env);
937 ret=g_shell_parse_argv (cmd, NULL, &argv, &gerr);
939 /* FIXME: Could do something with the
942 process_handle_data->exec_errno=gerr->code;
945 g_message (G_GNUC_PRETTY_FUNCTION ": forking");
948 _wapi_lookup_handle (GUINT_TO_POINTER (process_handle),
950 (gpointer *)&process_handle_data,
953 _wapi_lookup_handle (GUINT_TO_POINTER (thread_handle),
955 (gpointer *)&thread_handle_data,
958 /* Fork, exec cmd with args and optional env,
959 * and return the handles with pid and blank
964 process_handle_data->exec_errno=errno;
969 /* should we detach from the process
970 * group? We're already running
971 * without a controlling tty...
974 /* Connect stdin, stdout and stderr */
979 if(process_fork.inherit!=TRUE) {
980 /* FIXME: do something here */
983 /* Close all file descriptors */
984 for (i = getdtablesize () - 1; i > 2; i--) {
988 /* pass process and thread handle info
989 * to the child, so it doesn't have to
990 * do an expensive search over the
996 while(env[env_count]!=NULL) {
1000 env=(char **)g_renew (char **, env, env_count+3);
1002 env[env_count]=g_strdup_printf ("_WAPI_PROCESS_HANDLE=%d", process_handle);
1003 env[env_count+1]=g_strdup_printf ("_WAPI_THREAD_HANDLE=%d", thread_handle);
1004 env[env_count+2]=NULL;
1008 g_message (G_GNUC_PRETTY_FUNCTION
1009 ": exec()ing [%s] in dir [%s]",
1013 while(argv[i]!=NULL) {
1014 g_message ("arg %d: [%s]",
1020 while(env[i]!=NULL) {
1021 g_message ("env %d: [%s]",
1029 if(chdir (dir)==-1) {
1030 process_handle_data->exec_errno=errno;
1035 execve (argv[0], argv, env);
1038 process_handle_data->exec_errno=errno;
1044 /* store process name, based on the last section of the cmd */
1046 char *slash=strrchr (argv[0], '/');
1049 process_handle_data->proc_name=_wapi_handle_scratch_store (slash+1, strlen (slash+1));
1051 process_handle_data->proc_name=_wapi_handle_scratch_store (argv[0], strlen (argv[0]));
1055 /* These seem to be the defaults on w2k */
1056 process_handle_data->min_working_set=204800;
1057 process_handle_data->max_working_set=1413120;
1069 process_handle_data->id=pid;
1070 process_handle_data->main_thread=GUINT_TO_POINTER (thread_handle);
1072 gettimeofday (&tv, NULL);
1073 _wapi_timeval_to_filetime (&tv,
1074 &process_handle_data->create_time);
1076 /* FIXME: if env==0, inherit the env from the current
1079 process_handle_data->env=process_fork.env;
1081 thread_handle_data->process_handle=GUINT_TO_POINTER (process_handle);
1083 resp.u.process_fork.pid=pid;
1086 resp.u.process_fork.process_handle=process_handle;
1087 resp.u.process_fork.thread_handle=thread_handle;
1089 send_reply (channel, &resp);
1094 * @channel: The client to read the request from
1095 * @open_handles: An array of handles referenced by this client
1097 * Read a message (A WapiHandleRequest) from a client and dispatch
1098 * whatever it wants to the process_* calls.
1100 static void read_message (GIOChannel *channel, ChannelData *channel_data)
1102 WapiHandleRequest req;
1103 int fds[3]={0, 1, 2};
1105 gboolean has_fds=FALSE;
1108 ret=_wapi_daemon_request (g_io_channel_unix_get_fd (channel), &req,
1111 /* Other end went away */
1113 g_message ("Read 0 bytes on fd %d, closing it",
1114 g_io_channel_unix_get_fd (channel));
1116 rem_fd (channel, channel_data);
1121 g_message ("Process request %d", req.type);
1124 case WapiHandleRequestType_New:
1125 process_new (channel, channel_data, req.u.new.type);
1127 case WapiHandleRequestType_Open:
1129 g_assert(req.u.open.handle < _wapi_shared_data[0]->num_segments * _WAPI_HANDLES_PER_SEGMENT);
1131 process_open (channel, channel_data, req.u.open.handle);
1133 case WapiHandleRequestType_Close:
1135 g_assert(req.u.close.handle < _wapi_shared_data[0]->num_segments * _WAPI_HANDLES_PER_SEGMENT);
1137 process_close (channel, channel_data, req.u.close.handle);
1139 case WapiHandleRequestType_Scratch:
1140 process_scratch (channel, req.u.scratch.length);
1142 case WapiHandleRequestType_ScratchFree:
1143 process_scratch_free (channel, req.u.scratch_free.idx);
1145 case WapiHandleRequestType_ProcessFork:
1146 process_process_fork (channel, channel_data,
1147 req.u.process_fork, fds);
1149 case WapiHandleRequestType_ProcessKill:
1150 process_process_kill (channel, req.u.process_kill);
1152 case WapiHandleRequestType_Error:
1155 /* Catch bogus requests */
1156 /* FIXME: call rem_fd? */
1162 g_message (G_GNUC_PRETTY_FUNCTION ": closing %d", fds[0]);
1163 g_message (G_GNUC_PRETTY_FUNCTION ": closing %d", fds[1]);
1164 g_message (G_GNUC_PRETTY_FUNCTION ": closing %d", fds[2]);
1175 * @channel: The IO channel that is active
1176 * @condition: The condition that has been satisfied
1177 * @data: A pointer to an array of handles referenced by this client
1179 * The callback called by the main loop when there is activity on an
1182 static gboolean fd_activity (GIOChannel *channel, GIOCondition condition,
1185 int fd=g_io_channel_unix_get_fd (channel);
1186 ChannelData *channel_data=&channels[fd];
1187 GMainContext *context=data;
1189 if(condition & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
1191 g_message ("fd %d error", fd);
1194 rem_fd (channel, channel_data);
1198 if(condition & (G_IO_IN | G_IO_PRI)) {
1201 struct sockaddr addr;
1202 socklen_t addrlen=sizeof(struct sockaddr);
1204 newsock=accept (main_sock, &addr, &addrlen);
1206 g_critical ("accept error: %s",
1207 g_strerror (errno));
1213 g_message ("accept returning %d", newsock);
1216 add_fd (newsock, context);
1219 g_message ("reading data on fd %d", fd);
1222 read_message (channel, channel_data);
1227 return(FALSE); /* remove source */
1231 * _wapi_daemon_main:
1233 * Open socket, create shared mem segment and begin listening for
1236 void _wapi_daemon_main(gpointer data, gpointer scratch)
1238 struct sockaddr_un main_socket_address;
1240 GMainContext *context;
1243 g_message ("Starting up...");
1246 _wapi_shared_data[0]=data;
1247 _wapi_shared_scratch=scratch;
1248 _wapi_shared_scratch->is_shared=TRUE;
1250 /* Note that we've got the starting segment already */
1251 _wapi_shared_data[0]->num_segments=1;
1252 _wapi_shm_mapped_segments=1;
1256 main_sock=socket(PF_UNIX, SOCK_STREAM, 0);
1258 main_socket_address.sun_family=AF_UNIX;
1259 memcpy(main_socket_address.sun_path, _wapi_shared_data[0]->daemon,
1260 MONO_SIZEOF_SUNPATH);
1262 ret=bind(main_sock, (struct sockaddr *)&main_socket_address,
1263 sizeof(struct sockaddr_un));
1265 g_critical ("bind failed: %s", g_strerror (errno));
1266 _wapi_shared_data[0]->daemon_running=DAEMON_DIED_AT_STARTUP;
1274 ret=listen(main_sock, 5);
1276 g_critical ("listen failed: %s", g_strerror (errno));
1277 _wapi_shared_data[0]->daemon_running=DAEMON_DIED_AT_STARTUP;
1282 g_message("listening");
1285 context = g_main_context_new ();
1287 add_fd(main_sock, context);
1289 /* We're finished setting up, let everyone else know we're
1290 * ready. From now on, it's up to us to delete the shared
1291 * memory segment when appropriate.
1293 _wapi_shared_data[0]->daemon_running=DAEMON_RUNNING;
1296 if(check_processes==TRUE) {
1301 g_message ("polling");
1304 /* Block until something happens. We don't use
1305 * g_main_loop_run() because we rely on the SIGCHLD
1306 * signal interrupting poll() so we can reap child
1307 * processes as soon as they die, without burning cpu
1308 * time by polling the flag.
1310 g_main_context_iteration (context, TRUE);