From aa14ccd1e2edec2735f9200a4f2e5eee3b0abe09 Mon Sep 17 00:00:00 2001 From: Tom Tromey Date: Wed, 15 Aug 2012 13:17:37 -0600 Subject: [PATCH] Prepare process.c for threads by not having global select masks. The next step is to make it so selects can choose fds by thread. --- src/process.c | 295 ++++++++++++++++++++++++++++---------------------- 1 file changed, 165 insertions(+), 130 deletions(-) diff --git a/src/process.c b/src/process.c index 2a61b6da777..0d3355512b8 100644 --- a/src/process.c +++ b/src/process.c @@ -267,29 +267,7 @@ static void create_pty (Lisp_Object); static Lisp_Object get_process (register Lisp_Object name); static void exec_sentinel (Lisp_Object proc, Lisp_Object reason); -/* Mask of bits indicating the descriptors that we wait for input on. */ - -static SELECT_TYPE input_wait_mask; - -/* Mask that excludes keyboard input descriptor(s). */ - -static SELECT_TYPE non_keyboard_wait_mask; - -/* Mask that excludes process input descriptor(s). */ - -static SELECT_TYPE non_process_wait_mask; - -/* Mask for selecting for write. */ - -static SELECT_TYPE write_mask; - #ifdef NON_BLOCKING_CONNECT -/* Mask of bits indicating the descriptors that we wait for connect to - complete on. Once they complete, they are removed from this mask - and added to the input_wait_mask and non_keyboard_wait_mask. */ - -static SELECT_TYPE connect_wait_mask; - /* Number of bits set in connect_wait_mask. */ static int num_pending_connects; #endif /* NON_BLOCKING_CONNECT */ @@ -336,13 +314,27 @@ static int pty_max_bytes; +enum fd_bits +{ + /* Read from file descriptor. */ + FOR_READ = 1, + /* Write to file descriptor. */ + FOR_WRITE = 2, + /* This descriptor refers to a keyboard. Only valid if FOR_READ is + set. */ + KEYBOARD_FD = 4, + /* This descriptor refers to a process. */ + PROCESS_FD = 8, + /* A non-blocking connect. Only valid if FOR_WRITE is set. */ + NON_BLOCKING_CONNECT_FD = 16 +}; + static struct fd_callback_data { fd_callback func; void *data; -#define FOR_READ 1 -#define FOR_WRITE 2 - int condition; /* mask of the defines above. */ + /* Flags from enum fd_bits. */ + int flags; } fd_callback_info[MAXDESC]; @@ -357,7 +349,23 @@ add_read_fd (int fd, fd_callback func, void *data) fd_callback_info[fd].func = func; fd_callback_info[fd].data = data; - fd_callback_info[fd].condition |= FOR_READ; +} + +void +add_non_keyboard_read_fd (int fd) +{ + eassert (fd >= 0 && fd < MAXDESC); + eassert (fd_callback_info[fd].func == NULL); + fd_callback_info[fd].flags |= FOR_READ; + if (fd > max_input_desc) + max_input_desc = fd; +} + +void +add_process_read_fd (int fd) +{ + add_non_keyboard_read_fd (fd); + fd_callback_info[fd].flags |= PROCESS_FD; } /* Stop monitoring file descriptor FD for when read is possible. */ @@ -368,8 +376,7 @@ delete_read_fd (int fd) eassert (fd < MAXDESC); delete_keyboard_wait_descriptor (fd); - fd_callback_info[fd].condition &= ~FOR_READ; - if (fd_callback_info[fd].condition == 0) + if (fd_callback_info[fd].flags == 0) { fd_callback_info[fd].func = 0; fd_callback_info[fd].data = 0; @@ -383,13 +390,24 @@ void add_write_fd (int fd, fd_callback func, void *data) { eassert (fd < MAXDESC); - FD_SET (fd, &write_mask); if (fd > max_input_desc) max_input_desc = fd; fd_callback_info[fd].func = func; fd_callback_info[fd].data = data; - fd_callback_info[fd].condition |= FOR_WRITE; + fd_callback_info[fd].flags |= FOR_WRITE; +} + +void +add_non_blocking_write_fd (int fd) +{ + eassert (fd >= 0 && fd < MAXDESC); + eassert (fd_callback_info[fd].func == NULL); + + fd_callback_info[fd].flags |= FOR_WRITE | NON_BLOCKING_CONNECT_FD; + if (fd > max_input_desc) + max_input_desc = fd; + ++num_pending_connects; } /* Stop monitoring file descriptor FD for when write is possible. */ @@ -400,24 +418,87 @@ delete_write_fd (int fd) int lim = max_input_desc; eassert (fd < MAXDESC); - FD_CLR (fd, &write_mask); - fd_callback_info[fd].condition &= ~FOR_WRITE; - if (fd_callback_info[fd].condition == 0) + if ((fd_callback_info[fd].flags & NON_BLOCKING_CONNECT_FD) != 0) + { + if (--num_pending_connects < 0) + abort (); + } + fd_callback_info[fd].flags &= ~(FOR_WRITE | NON_BLOCKING_CONNECT_FD); + if (fd_callback_info[fd].flags == 0) { fd_callback_info[fd].func = 0; fd_callback_info[fd].data = 0; if (fd == max_input_desc) - for (fd = lim; fd >= 0; fd--) - if (FD_ISSET (fd, &input_wait_mask) || FD_ISSET (fd, &write_mask)) - { - max_input_desc = fd; - break; - } + { + for (fd = max_input_desc; fd >= 0; --fd) + { + if (fd_callback_info[fd].flags != 0) + { + max_input_desc = fd; + break; + } + } + } + } +} + +static void +compute_input_wait_mask (SELECT_TYPE *mask) +{ + int fd; + FD_ZERO (mask); + for (fd = 0; fd < max (max_process_desc, max_input_desc); ++fd) + { + if ((fd_callback_info[fd].flags & FOR_READ) != 0) + FD_SET (fd, mask); } } +static void +compute_non_process_wait_mask (SELECT_TYPE *mask) +{ + int fd; + + FD_ZERO (mask); + for (fd = 0; fd < max (max_process_desc, max_input_desc); ++fd) + { + if ((fd_callback_info[fd].flags & FOR_READ) != 0 + && (fd_callback_info[fd].flags & PROCESS_FD) == 0) + FD_SET (fd, mask); + } +} + +static void +compute_non_keyboard_wait_mask (SELECT_TYPE *mask) +{ + int fd; + + FD_ZERO (mask); + for (fd = 0; fd < max (max_process_desc, max_input_desc); ++fd) + { + if ((fd_callback_info[fd].flags & FOR_READ) != 0 + && (fd_callback_info[fd].flags & KEYBOARD_FD) == 0) + FD_SET (fd, mask); + } +} + +static void +compute_write_mask (SELECT_TYPE *mask) +{ + int fd; + + FD_ZERO (mask); + for (fd = 0; fd < max (max_process_desc, max_input_desc); ++fd) + { + if ((fd_callback_info[fd].flags & FOR_WRITE) != 0) + FD_SET (fd, mask); + } +} + + + /* Compute the Lisp form of the process status, p->status, from the numeric status that was returned by `wait'. */ @@ -961,17 +1042,11 @@ The string argument is normally a multibyte string, except: if (p->infd >= 0) { if (EQ (filter, Qt) && !EQ (p->status, Qlisten)) - { - FD_CLR (p->infd, &input_wait_mask); - FD_CLR (p->infd, &non_keyboard_wait_mask); - } + delete_read_fd (p->infd); else if (EQ (p->filter, Qt) /* Network or serial process not stopped: */ && !EQ (p->command, Qt)) - { - FD_SET (p->infd, &input_wait_mask); - FD_SET (p->infd, &non_keyboard_wait_mask); - } + delete_read_fd (p->infd); } PSET (p, filter, filter); @@ -1650,10 +1725,7 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir) #endif /* HAVE_WORKING_VFORK */ pthread_sigmask (SIG_BLOCK, &blocked, &procmask); - FD_SET (inchannel, &input_wait_mask); - FD_SET (inchannel, &non_keyboard_wait_mask); - if (inchannel > max_process_desc) - max_process_desc = inchannel; + add_non_keyboard_read_fd (inchannel); /* Until we store the proper pid, enable sigchld_handler to recognize an unknown pid as standing for this process. @@ -1968,10 +2040,7 @@ create_pty (Lisp_Object process) PSET (XPROCESS (process), status, Qrun); setup_process_coding_systems (process); - FD_SET (inchannel, &input_wait_mask); - FD_SET (inchannel, &non_keyboard_wait_mask); - if (inchannel > max_process_desc) - max_process_desc = inchannel; + add_non_keyboard_read_fd (inchannel); XPROCESS (process)->pid = -2; #ifdef HAVE_PTYS @@ -2616,10 +2685,7 @@ usage: (make-serial-process &rest ARGS) */) p->pty_flag = 0; if (!EQ (p->command, Qt)) - { - FD_SET (fd, &input_wait_mask); - FD_SET (fd, &non_keyboard_wait_mask); - } + add_non_keyboard_read_fd (fd); if (BUFFERP (buffer)) { @@ -3431,12 +3497,8 @@ usage: (make-network-process &rest ARGS) */) in that case, we still need to signal this like a non-blocking connection. */ PSET (p, status, Qconnect); - if (!FD_ISSET (inch, &connect_wait_mask)) - { - FD_SET (inch, &connect_wait_mask); - FD_SET (inch, &write_mask); - num_pending_connects++; - } + if ((fd_callback_info[inch].flags & NON_BLOCKING_CONNECT_FD) == 0) + add_non_blocking_write_fd (inch); } else #endif @@ -3444,10 +3506,7 @@ usage: (make-network-process &rest ARGS) */) still listen for incoming connects unless it is stopped. */ if ((!EQ (p->filter, Qt) && !EQ (p->command, Qt)) || (EQ (p->status, Qlisten) && NILP (p->command))) - { - FD_SET (inch, &input_wait_mask); - FD_SET (inch, &non_keyboard_wait_mask); - } + add_non_keyboard_read_fd (inch); if (inch > max_process_desc) max_process_desc = inch; @@ -3892,16 +3951,10 @@ deactivate_process (Lisp_Object proc) } #endif chan_process[inchannel] = Qnil; - FD_CLR (inchannel, &input_wait_mask); - FD_CLR (inchannel, &non_keyboard_wait_mask); + delete_read_fd (inchannel); #ifdef NON_BLOCKING_CONNECT - if (FD_ISSET (inchannel, &connect_wait_mask)) - { - FD_CLR (inchannel, &connect_wait_mask); - FD_CLR (inchannel, &write_mask); - if (--num_pending_connects < 0) - abort (); - } + if ((fd_callback_info[inchannel].flags & NON_BLOCKING_CONNECT_FD) != 0) + delete_write_fd (inchannel); #endif if (inchannel == max_process_desc) { @@ -4165,13 +4218,7 @@ server_accept_connection (Lisp_Object server, int channel) /* Client processes for accepted connections are not stopped initially. */ if (!EQ (p->filter, Qt)) - { - FD_SET (s, &input_wait_mask); - FD_SET (s, &non_keyboard_wait_mask); - } - - if (s > max_process_desc) - max_process_desc = s; + add_non_keyboard_read_fd (s); /* Setup coding system for new process based on server process. This seems to be the proper thing to do, as the coding system @@ -4433,8 +4480,8 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, if (kbd_on_hold_p ()) FD_ZERO (&Atemp); else - Atemp = input_wait_mask; - Ctemp = write_mask; + compute_input_wait_mask (&Atemp); + compute_write_mask (&Ctemp); timeout = make_emacs_time (0, 0); if ((pselect (max (max_process_desc, max_input_desc) + 1, @@ -4512,17 +4559,17 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, } else if (!NILP (wait_for_cell)) { - Available = non_process_wait_mask; + compute_non_process_wait_mask (&Available); check_delay = 0; check_write = 0; } else { if (! read_kbd) - Available = non_keyboard_wait_mask; + compute_non_keyboard_wait_mask (&Available); else - Available = input_wait_mask; - Writeok = write_mask; + compute_input_wait_mask (&Available); + compute_write_mask (&Writeok); #ifdef SELECT_CANT_DO_WRITE_MASK check_write = 0; #else @@ -4790,19 +4837,19 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, struct fd_callback_data *d = &fd_callback_info[channel]; if (FD_ISSET (channel, &Available) && d->func != 0 - && (d->condition & FOR_READ) != 0) + && (d->flags & FOR_READ) != 0) d->func (channel, d->data, 1); if (FD_ISSET (channel, &Writeok) && d->func != 0 - && (d->condition & FOR_WRITE) != 0) + && (d->flags & FOR_WRITE) != 0) d->func (channel, d->data, 0); } for (channel = 0; channel <= max_process_desc; channel++) { if (FD_ISSET (channel, &Available) - && FD_ISSET (channel, &non_keyboard_wait_mask) - && !FD_ISSET (channel, &non_process_wait_mask)) + && ((fd_callback_info[channel].flags & (KEYBOARD_FD | PROCESS_FD)) + == PROCESS_FD)) { int nread; @@ -4880,8 +4927,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, /* Clear the descriptor now, so we only raise the signal once. */ - FD_CLR (channel, &input_wait_mask); - FD_CLR (channel, &non_keyboard_wait_mask); + delete_read_fd (channel); if (p->pid == -2) { @@ -4915,14 +4961,12 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, } #ifdef NON_BLOCKING_CONNECT if (FD_ISSET (channel, &Writeok) - && FD_ISSET (channel, &connect_wait_mask)) + && (fd_callback_info[channel].flags + & NON_BLOCKING_CONNECT_FD) != 0) { struct Lisp_Process *p; - FD_CLR (channel, &connect_wait_mask); - FD_CLR (channel, &write_mask); - if (--num_pending_connects < 0) - abort (); + delete_write_fd (channel); proc = chan_process[channel]; if (NILP (proc)) @@ -4970,10 +5014,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, from the process before calling the sentinel. */ exec_sentinel (proc, build_string ("open\n")); if (!EQ (p->filter, Qt) && !EQ (p->command, Qt)) - { - FD_SET (p->infd, &input_wait_mask); - FD_SET (p->infd, &non_keyboard_wait_mask); - } + delete_read_fd (p->infd); } } #endif /* NON_BLOCKING_CONNECT */ @@ -6014,10 +6055,7 @@ traffic. */) p = XPROCESS (process); if (NILP (p->command) && p->infd >= 0) - { - FD_CLR (p->infd, &input_wait_mask); - FD_CLR (p->infd, &non_keyboard_wait_mask); - } + delete_read_fd (p->infd); PSET (p, command, Qt); return process; } @@ -6045,8 +6083,7 @@ traffic. */) && p->infd >= 0 && (!EQ (p->filter, Qt) || EQ (p->status, Qlisten))) { - FD_SET (p->infd, &input_wait_mask); - FD_SET (p->infd, &non_keyboard_wait_mask); + add_non_keyboard_read_fd (p->infd); #ifdef WINDOWSNT if (fd_info[ p->infd ].flags & FILE_SERIAL) PurgeComm (fd_info[ p->infd ].hnd, PURGE_RXABORT | PURGE_RXCLEAR); @@ -6419,10 +6456,7 @@ sigchld_handler (int signo) /* We use clear_desc_flag to avoid a compiler bug in Microsoft C. */ if (clear_desc_flag) - { - FD_CLR (p->infd, &input_wait_mask); - FD_CLR (p->infd, &non_keyboard_wait_mask); - } + delete_read_fd (p->infd); /* Tell wait_reading_process_output that it needs to wake up and look around. */ @@ -6796,8 +6830,8 @@ keyboard_bit_set (fd_set *mask) int fd; for (fd = 0; fd <= max_input_desc; fd++) - if (FD_ISSET (fd, mask) && FD_ISSET (fd, &input_wait_mask) - && !FD_ISSET (fd, &non_keyboard_wait_mask)) + if (FD_ISSET (fd, mask) + && ((fd_callback_info[fd].flags & KEYBOARD_FD) != 0)) return 1; return 0; @@ -7042,8 +7076,8 @@ void add_keyboard_wait_descriptor (int desc) { #ifdef subprocesses /* actually means "not MSDOS" */ - FD_SET (desc, &input_wait_mask); - FD_SET (desc, &non_process_wait_mask); + eassert (desc >= 0 && desc < MAXDESC); + fd_callback_info[desc].flags |= FOR_READ | KEYBOARD_FD; if (desc > max_input_desc) max_input_desc = desc; #endif @@ -7058,13 +7092,19 @@ delete_keyboard_wait_descriptor (int desc) int fd; int lim = max_input_desc; - FD_CLR (desc, &input_wait_mask); - FD_CLR (desc, &non_process_wait_mask); + fd_callback_info[desc].flags &= ~(FOR_READ | KEYBOARD_FD | PROCESS_FD); if (desc == max_input_desc) - for (fd = 0; fd < lim; fd++) - if (FD_ISSET (fd, &input_wait_mask) || FD_ISSET (fd, &write_mask)) - max_input_desc = fd; + { + for (fd = max_input_desc; fd >= 0; --fd) + { + if (fd_callback_info[desc].flags != 0) + { + max_input_desc = fd; + break; + } + } + } #endif } @@ -7320,15 +7360,10 @@ init_process_emacs (void) signal (SIGCHLD, sigchld_handler); #endif - FD_ZERO (&input_wait_mask); - FD_ZERO (&non_keyboard_wait_mask); - FD_ZERO (&non_process_wait_mask); - FD_ZERO (&write_mask); max_process_desc = 0; memset (fd_callback_info, 0, sizeof (fd_callback_info)); #ifdef NON_BLOCKING_CONNECT - FD_ZERO (&connect_wait_mask); num_pending_connects = 0; #endif -- 2.39.5