aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorTom Tromey2012-08-15 13:19:24 -0600
committerTom Tromey2012-08-15 13:19:24 -0600
commit6c0d5ae50789673f53c834084bbe1f62f5a62731 (patch)
tree0f976b74b292b2a4714470eebb2ce39548d47678 /src
parentaa14ccd1e2edec2735f9200a4f2e5eee3b0abe09 (diff)
downloademacs-6c0d5ae50789673f53c834084bbe1f62f5a62731.tar.gz
emacs-6c0d5ae50789673f53c834084bbe1f62f5a62731.zip
process changes
This changes wait_reading_process_output to handle threads better. It introduces a wrapper for select that releases the global lock, and it ensures that only a single thread can select a given file descriptor at a time. This also adds the thread-locking feature to processes. By default a process can only have its output accepted by the thread that created it. This can be changed using set-process-thread. (If the thread exits, the process is again available for waiting by any thread.) Note that thread-signal will not currently interrupt a thread blocked on select. I'll fix this later.
Diffstat (limited to 'src')
-rw-r--r--src/process.c175
-rw-r--r--src/process.h5
-rw-r--r--src/thread.c47
-rw-r--r--src/thread.h22
4 files changed, 221 insertions, 28 deletions
diff --git a/src/process.c b/src/process.c
index 0d3355512b8..ada673e3c34 100644
--- a/src/process.c
+++ b/src/process.c
@@ -335,6 +335,13 @@ static struct fd_callback_data
335 void *data; 335 void *data;
336 /* Flags from enum fd_bits. */ 336 /* Flags from enum fd_bits. */
337 int flags; 337 int flags;
338 /* If this fd is locked to a certain thread, this points to it.
339 Otherwise, this is NULL. If an fd is locked to a thread, then
340 only that thread is permitted to wait on it. */
341 struct thread_state *thread;
342 /* If this fd is currently being selected on by a thread, this
343 points to the thread. Otherwise it is NULL. */
344 struct thread_state *waiting_thread;
338} fd_callback_info[MAXDESC]; 345} fd_callback_info[MAXDESC];
339 346
340 347
@@ -451,8 +458,17 @@ compute_input_wait_mask (SELECT_TYPE *mask)
451 FD_ZERO (mask); 458 FD_ZERO (mask);
452 for (fd = 0; fd < max (max_process_desc, max_input_desc); ++fd) 459 for (fd = 0; fd < max (max_process_desc, max_input_desc); ++fd)
453 { 460 {
461 if (fd_callback_info[fd].thread != NULL
462 && fd_callback_info[fd].thread != current_thread)
463 continue;
464 if (fd_callback_info[fd].waiting_thread != NULL
465 && fd_callback_info[fd].waiting_thread != current_thread)
466 continue;
454 if ((fd_callback_info[fd].flags & FOR_READ) != 0) 467 if ((fd_callback_info[fd].flags & FOR_READ) != 0)
455 FD_SET (fd, mask); 468 {
469 FD_SET (fd, mask);
470 fd_callback_info[fd].waiting_thread = current_thread;
471 }
456 } 472 }
457} 473}
458 474
@@ -464,9 +480,18 @@ compute_non_process_wait_mask (SELECT_TYPE *mask)
464 FD_ZERO (mask); 480 FD_ZERO (mask);
465 for (fd = 0; fd < max (max_process_desc, max_input_desc); ++fd) 481 for (fd = 0; fd < max (max_process_desc, max_input_desc); ++fd)
466 { 482 {
483 if (fd_callback_info[fd].thread != NULL
484 && fd_callback_info[fd].thread != current_thread)
485 continue;
486 if (fd_callback_info[fd].waiting_thread != NULL
487 && fd_callback_info[fd].waiting_thread != current_thread)
488 continue;
467 if ((fd_callback_info[fd].flags & FOR_READ) != 0 489 if ((fd_callback_info[fd].flags & FOR_READ) != 0
468 && (fd_callback_info[fd].flags & PROCESS_FD) == 0) 490 && (fd_callback_info[fd].flags & PROCESS_FD) == 0)
469 FD_SET (fd, mask); 491 {
492 FD_SET (fd, mask);
493 fd_callback_info[fd].waiting_thread = current_thread;
494 }
470 } 495 }
471} 496}
472 497
@@ -478,9 +503,18 @@ compute_non_keyboard_wait_mask (SELECT_TYPE *mask)
478 FD_ZERO (mask); 503 FD_ZERO (mask);
479 for (fd = 0; fd < max (max_process_desc, max_input_desc); ++fd) 504 for (fd = 0; fd < max (max_process_desc, max_input_desc); ++fd)
480 { 505 {
506 if (fd_callback_info[fd].thread != NULL
507 && fd_callback_info[fd].thread != current_thread)
508 continue;
509 if (fd_callback_info[fd].waiting_thread != NULL
510 && fd_callback_info[fd].waiting_thread != current_thread)
511 continue;
481 if ((fd_callback_info[fd].flags & FOR_READ) != 0 512 if ((fd_callback_info[fd].flags & FOR_READ) != 0
482 && (fd_callback_info[fd].flags & KEYBOARD_FD) == 0) 513 && (fd_callback_info[fd].flags & KEYBOARD_FD) == 0)
483 FD_SET (fd, mask); 514 {
515 FD_SET (fd, mask);
516 fd_callback_info[fd].waiting_thread = current_thread;
517 }
484 } 518 }
485} 519}
486 520
@@ -492,12 +526,31 @@ compute_write_mask (SELECT_TYPE *mask)
492 FD_ZERO (mask); 526 FD_ZERO (mask);
493 for (fd = 0; fd < max (max_process_desc, max_input_desc); ++fd) 527 for (fd = 0; fd < max (max_process_desc, max_input_desc); ++fd)
494 { 528 {
529 if (fd_callback_info[fd].thread != NULL
530 && fd_callback_info[fd].thread != current_thread)
531 continue;
532 if (fd_callback_info[fd].waiting_thread != NULL
533 && fd_callback_info[fd].waiting_thread != current_thread)
534 continue;
495 if ((fd_callback_info[fd].flags & FOR_WRITE) != 0) 535 if ((fd_callback_info[fd].flags & FOR_WRITE) != 0)
496 FD_SET (fd, mask); 536 {
537 FD_SET (fd, mask);
538 fd_callback_info[fd].waiting_thread = current_thread;
539 }
497 } 540 }
498} 541}
499 542
543static void
544clear_waiting_thread_info (void)
545{
546 int fd;
500 547
548 for (fd = 0; fd < max (max_process_desc, max_input_desc); ++fd)
549 {
550 if (fd_callback_info[fd].waiting_thread == current_thread)
551 fd_callback_info[fd].waiting_thread = NULL;
552 }
553}
501 554
502 555
503/* Compute the Lisp form of the process status, p->status, from 556/* Compute the Lisp form of the process status, p->status, from
@@ -709,6 +762,7 @@ make_process (Lisp_Object name)
709 Lisp data to nil, so do it only for slots which should not be nil. */ 762 Lisp data to nil, so do it only for slots which should not be nil. */
710 PSET (p, status, Qrun); 763 PSET (p, status, Qrun);
711 PSET (p, mark, Fmake_marker ()); 764 PSET (p, mark, Fmake_marker ());
765 PSET (p, thread, Fcurrent_thread ());
712 766
713 /* Initialize non-Lisp data. Note that allocate_process zeroes out all 767 /* Initialize non-Lisp data. Note that allocate_process zeroes out all
714 non-Lisp data, so do it only for slots which should not be zero. */ 768 non-Lisp data, so do it only for slots which should not be zero. */
@@ -746,6 +800,27 @@ remove_process (register Lisp_Object proc)
746 deactivate_process (proc); 800 deactivate_process (proc);
747} 801}
748 802
803void
804update_processes_for_thread_death (Lisp_Object dying_thread)
805{
806 Lisp_Object pair;
807
808 for (pair = Vprocess_alist; !NILP (pair); pair = XCDR (pair))
809 {
810 Lisp_Object process = XCDR (XCAR (pair));
811 if (EQ (XPROCESS (process)->thread, dying_thread))
812 {
813 struct Lisp_Process *proc = XPROCESS (process);
814
815 proc->thread = Qnil;
816 if (proc->infd >= 0)
817 fd_callback_info[proc->infd].thread = NULL;
818 if (proc->outfd >= 0)
819 fd_callback_info[proc->outfd].thread = NULL;
820 }
821 }
822}
823
749 824
750DEFUN ("processp", Fprocessp, Sprocessp, 1, 1, 0, 825DEFUN ("processp", Fprocessp, Sprocessp, 1, 1, 0,
751 doc: /* Return t if OBJECT is a process. */) 826 doc: /* Return t if OBJECT is a process. */)
@@ -1094,6 +1169,42 @@ See `set-process-sentinel' for more info on sentinels. */)
1094 return XPROCESS (process)->sentinel; 1169 return XPROCESS (process)->sentinel;
1095} 1170}
1096 1171
1172DEFUN ("set-process-thread", Fset_process_thread, Sset_process_thread,
1173 2, 2, 0,
1174 doc: /* FIXME */)
1175 (Lisp_Object process, Lisp_Object thread)
1176{
1177 struct Lisp_Process *proc;
1178 struct thread_state *tstate;
1179
1180 CHECK_PROCESS (process);
1181 if (NILP (thread))
1182 tstate = NULL;
1183 else
1184 {
1185 CHECK_THREAD (thread);
1186 tstate = XTHREAD (thread);
1187 }
1188
1189 proc = XPROCESS (process);
1190 proc->thread = thread;
1191 if (proc->infd >= 0)
1192 fd_callback_info[proc->infd].thread = tstate;
1193 if (proc->outfd >= 0)
1194 fd_callback_info[proc->outfd].thread = tstate;
1195
1196 return thread;
1197}
1198
1199DEFUN ("process-thread", Fprocess_thread, Sprocess_thread,
1200 1, 1, 0,
1201 doc: /* FIXME */)
1202 (Lisp_Object process)
1203{
1204 CHECK_PROCESS (process);
1205 return XPROCESS (process)->thread;
1206}
1207
1097DEFUN ("set-process-window-size", Fset_process_window_size, 1208DEFUN ("set-process-window-size", Fset_process_window_size,
1098 Sset_process_window_size, 3, 3, 0, 1209 Sset_process_window_size, 3, 3, 0,
1099 doc: /* Tell PROCESS that it has logical window size HEIGHT and WIDTH. */) 1210 doc: /* Tell PROCESS that it has logical window size HEIGHT and WIDTH. */)
@@ -3993,7 +4104,17 @@ Return non-nil if we received any output before the timeout expired. */)
3993 int nsecs; 4104 int nsecs;
3994 4105
3995 if (! NILP (process)) 4106 if (! NILP (process))
3996 CHECK_PROCESS (process); 4107 {
4108 struct Lisp_Process *procp;
4109
4110 CHECK_PROCESS (process);
4111 procp = XPROCESS (process);
4112
4113 /* Can't wait for a process that is dedicated to a different
4114 thread. */
4115 if (!EQ (procp->thread, Qnil) && !EQ (procp->thread, Fcurrent_thread ()))
4116 error ("FIXME");
4117 }
3997 else 4118 else
3998 just_this_one = Qnil; 4119 just_this_one = Qnil;
3999 4120
@@ -4249,20 +4370,10 @@ server_accept_connection (Lisp_Object server, int channel)
4249 build_string ("\n"))); 4370 build_string ("\n")));
4250} 4371}
4251 4372
4252/* This variable is different from waiting_for_input in keyboard.c.
4253 It is used to communicate to a lisp process-filter/sentinel (via the
4254 function Fwaiting_for_user_input_p below) whether Emacs was waiting
4255 for user-input when that process-filter was called.
4256 waiting_for_input cannot be used as that is by definition 0 when
4257 lisp code is being evalled.
4258 This is also used in record_asynch_buffer_change.
4259 For that purpose, this must be 0
4260 when not inside wait_reading_process_output. */
4261static int waiting_for_user_input_p;
4262
4263static Lisp_Object 4373static Lisp_Object
4264wait_reading_process_output_unwind (Lisp_Object data) 4374wait_reading_process_output_unwind (Lisp_Object data)
4265{ 4375{
4376 clear_waiting_thread_info ();
4266 waiting_for_user_input_p = XINT (data); 4377 waiting_for_user_input_p = XINT (data);
4267 return Qnil; 4378 return Qnil;
4268} 4379}
@@ -4329,6 +4440,10 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
4329 int got_some_input = 0; 4440 int got_some_input = 0;
4330 ptrdiff_t count = SPECPDL_INDEX (); 4441 ptrdiff_t count = SPECPDL_INDEX ();
4331 4442
4443 eassert (wait_proc == NULL
4444 || EQ (wait_proc->thread, Qnil)
4445 || XTHREAD (wait_proc->thread) == current_thread);
4446
4332 FD_ZERO (&Available); 4447 FD_ZERO (&Available);
4333 FD_ZERO (&Writeok); 4448 FD_ZERO (&Writeok);
4334 4449
@@ -4484,14 +4599,15 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
4484 compute_write_mask (&Ctemp); 4599 compute_write_mask (&Ctemp);
4485 4600
4486 timeout = make_emacs_time (0, 0); 4601 timeout = make_emacs_time (0, 0);
4487 if ((pselect (max (max_process_desc, max_input_desc) + 1, 4602 if ((thread_select (pselect,
4488 &Atemp, 4603 max (max_process_desc, max_input_desc) + 1,
4604 &Atemp,
4489#ifdef NON_BLOCKING_CONNECT 4605#ifdef NON_BLOCKING_CONNECT
4490 (num_pending_connects > 0 ? &Ctemp : NULL), 4606 (num_pending_connects > 0 ? &Ctemp : NULL),
4491#else 4607#else
4492 NULL, 4608 NULL,
4493#endif 4609#endif
4494 NULL, &timeout, NULL) 4610 NULL, &timeout, NULL)
4495 <= 0)) 4611 <= 0))
4496 { 4612 {
4497 /* It's okay for us to do this and then continue with 4613 /* It's okay for us to do this and then continue with
@@ -4639,17 +4755,18 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
4639 process_output_skip = 0; 4755 process_output_skip = 0;
4640 } 4756 }
4641#endif 4757#endif
4758 nfds = thread_select (
4642#if defined (USE_GTK) || defined (HAVE_GCONF) || defined (HAVE_GSETTINGS) 4759#if defined (USE_GTK) || defined (HAVE_GCONF) || defined (HAVE_GSETTINGS)
4643 nfds = xg_select 4760 xg_select
4644#elif defined (HAVE_NS) 4761#elif defined (HAVE_NS)
4645 nfds = ns_select 4762 ns_select
4646#else 4763#else
4647 nfds = pselect 4764 pselect
4648#endif 4765#endif
4649 (max (max_process_desc, max_input_desc) + 1, 4766 , max (max_process_desc, max_input_desc) + 1,
4650 &Available, 4767 &Available,
4651 (check_write ? &Writeok : (SELECT_TYPE *)0), 4768 (check_write ? &Writeok : (SELECT_TYPE *)0),
4652 NULL, &timeout, NULL); 4769 NULL, &timeout, NULL);
4653 4770
4654#ifdef HAVE_GNUTLS 4771#ifdef HAVE_GNUTLS
4655 /* GnuTLS buffers data internally. In lowat mode it leaves 4772 /* GnuTLS buffers data internally. In lowat mode it leaves
@@ -7597,6 +7714,8 @@ The variable takes effect when `start-process' is called. */);
7597 defsubr (&Sprocess_filter); 7714 defsubr (&Sprocess_filter);
7598 defsubr (&Sset_process_sentinel); 7715 defsubr (&Sset_process_sentinel);
7599 defsubr (&Sprocess_sentinel); 7716 defsubr (&Sprocess_sentinel);
7717 defsubr (&Sset_process_thread);
7718 defsubr (&Sprocess_thread);
7600 defsubr (&Sset_process_window_size); 7719 defsubr (&Sset_process_window_size);
7601 defsubr (&Sset_process_inherit_coding_system_flag); 7720 defsubr (&Sset_process_inherit_coding_system_flag);
7602 defsubr (&Sset_process_query_on_exit_flag); 7721 defsubr (&Sset_process_query_on_exit_flag);
diff --git a/src/process.h b/src/process.h
index 43cc7ea33c0..1ddfe915357 100644
--- a/src/process.h
+++ b/src/process.h
@@ -103,6 +103,9 @@ struct Lisp_Process
103 Lisp_Object gnutls_cred_type; 103 Lisp_Object gnutls_cred_type;
104#endif 104#endif
105 105
106 /* The thread a process is linked to, or nil for any thread. */
107 Lisp_Object thread;
108
106 /* After this point, there are no Lisp_Objects any more. */ 109 /* After this point, there are no Lisp_Objects any more. */
107 /* alloc.c assumes that `pid' is the first such non-Lisp slot. */ 110 /* alloc.c assumes that `pid' is the first such non-Lisp slot. */
108 111
@@ -208,3 +211,5 @@ extern void add_read_fd (int fd, fd_callback func, void *data);
208extern void delete_read_fd (int fd); 211extern void delete_read_fd (int fd);
209extern void add_write_fd (int fd, fd_callback func, void *data); 212extern void add_write_fd (int fd, fd_callback func, void *data);
210extern void delete_write_fd (int fd); 213extern void delete_write_fd (int fd);
214
215extern void update_processes_for_thread_death (Lisp_Object);
diff --git a/src/thread.c b/src/thread.c
index 40c8be9f4d5..be98b4aae1d 100644
--- a/src/thread.c
+++ b/src/thread.c
@@ -22,6 +22,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
22#include "lisp.h" 22#include "lisp.h"
23#include "character.h" 23#include "character.h"
24#include "buffer.h" 24#include "buffer.h"
25#include "process.h"
25 26
26/* FIXME */ 27/* FIXME */
27extern void unbind_for_thread_switch (void); 28extern void unbind_for_thread_switch (void);
@@ -176,6 +177,50 @@ acquire_global_lock (struct thread_state *self)
176 177
177 178
178 179
180struct select_args
181{
182 select_func *func;
183 int max_fds;
184 SELECT_TYPE *rfds;
185 SELECT_TYPE *wfds;
186 SELECT_TYPE *efds;
187 EMACS_TIME *timeout;
188 sigset_t *sigmask;
189 int result;
190};
191
192static void
193really_call_select (void *arg)
194{
195 struct select_args *sa = arg;
196 struct thread_state *self = current_thread;
197
198 release_global_lock ();
199 sa->result = (sa->func) (sa->max_fds, sa->rfds, sa->wfds, sa->efds,
200 sa->timeout, sa->sigmask);
201 acquire_global_lock (self);
202}
203
204int
205thread_select (select_func *func, int max_fds, SELECT_TYPE *rfds,
206 SELECT_TYPE *wfds, SELECT_TYPE *efds, EMACS_TIME *timeout,
207 sigset_t *sigmask)
208{
209 struct select_args sa;
210
211 sa.func = func;
212 sa.max_fds = max_fds;
213 sa.rfds = rfds;
214 sa.wfds = wfds;
215 sa.efds = efds;
216 sa.timeout = timeout;
217 sa.sigmask = sigmask;
218 flush_stack_call_func (really_call_select, &sa);
219 return sa.result;
220}
221
222
223
179static void 224static void
180mark_one_thread (struct thread_state *thread) 225mark_one_thread (struct thread_state *thread)
181{ 226{
@@ -315,6 +360,8 @@ run_thread (void *state)
315 360
316 unbind_for_thread_switch (); 361 unbind_for_thread_switch ();
317 362
363 update_processes_for_thread_death (Fcurrent_thread ());
364
318 /* Unlink this thread from the list of all threads. */ 365 /* Unlink this thread from the list of all threads. */
319 for (iter = &all_threads; *iter != self; iter = &(*iter)->next_thread) 366 for (iter = &all_threads; *iter != self; iter = &(*iter)->next_thread)
320 ; 367 ;
diff --git a/src/thread.h b/src/thread.h
index d21887a0928..9db3c795653 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -21,6 +21,9 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
21 21
22#include "regex.h" 22#include "regex.h"
23 23
24#include "sysselect.h" /* FIXME */
25#include "systime.h" /* FIXME */
26
24struct thread_state 27struct thread_state
25{ 28{
26 struct vectorlike_header header; 29 struct vectorlike_header header;
@@ -156,6 +159,18 @@ struct thread_state
156 /*re_char*/ unsigned char *m_whitespace_regexp; 159 /*re_char*/ unsigned char *m_whitespace_regexp;
157#define whitespace_regexp (current_thread->m_whitespace_regexp) 160#define whitespace_regexp (current_thread->m_whitespace_regexp)
158 161
162 /* This variable is different from waiting_for_input in keyboard.c.
163 It is used to communicate to a lisp process-filter/sentinel (via the
164 function Fwaiting_for_user_input_p) whether Emacs was waiting
165 for user-input when that process-filter was called.
166 waiting_for_input cannot be used as that is by definition 0 when
167 lisp code is being evalled.
168 This is also used in record_asynch_buffer_change.
169 For that purpose, this must be 0
170 when not inside wait_reading_process_output. */
171 int m_waiting_for_user_input_p;
172#define waiting_for_user_input_p (current_thread->m_waiting_for_user_input_p)
173
159 /* The OS identifier for this thread. */ 174 /* The OS identifier for this thread. */
160 sys_thread_t thread_id; 175 sys_thread_t thread_id;
161 176
@@ -194,4 +209,11 @@ extern void init_threads_once (void);
194extern void init_threads (void); 209extern void init_threads (void);
195extern void syms_of_threads (void); 210extern void syms_of_threads (void);
196 211
212typedef int select_func (int, SELECT_TYPE *, SELECT_TYPE *, SELECT_TYPE *,
213 EMACS_TIME *, sigset_t *);
214
215int thread_select (select_func *func, int max_fds, SELECT_TYPE *rfds,
216 SELECT_TYPE *wfds, SELECT_TYPE *efds, EMACS_TIME *timeout,
217 sigset_t *sigmask);
218
197#endif /* THREAD_H */ 219#endif /* THREAD_H */