diff options
| -rw-r--r-- | doc/lispref/elisp.texi | 3 | ||||
| -rw-r--r-- | doc/lispref/objects.texi | 69 | ||||
| -rw-r--r-- | src/lisp.h | 2 | ||||
| -rw-r--r-- | src/regex.c | 1 | ||||
| -rw-r--r-- | src/thread.c | 71 | ||||
| -rw-r--r-- | src/xgselect.c | 3 |
6 files changed, 114 insertions, 35 deletions
diff --git a/doc/lispref/elisp.texi b/doc/lispref/elisp.texi index 415dbe66fac..4a53a0cd364 100644 --- a/doc/lispref/elisp.texi +++ b/doc/lispref/elisp.texi | |||
| @@ -349,6 +349,9 @@ Editing Types | |||
| 349 | * Window Configuration Type:: Recording the way a frame is subdivided. | 349 | * Window Configuration Type:: Recording the way a frame is subdivided. |
| 350 | * Frame Configuration Type:: Recording the status of all frames. | 350 | * Frame Configuration Type:: Recording the status of all frames. |
| 351 | * Process Type:: A subprocess of Emacs running on the underlying OS. | 351 | * Process Type:: A subprocess of Emacs running on the underlying OS. |
| 352 | * Thread Type:: A thread of Emacs Lisp execution. | ||
| 353 | * Mutex Type:: An exclusive lock for thread synchronization. | ||
| 354 | * Condition Variable Type:: Condition variable for thread synchronization. | ||
| 352 | * Stream Type:: Receive or send characters. | 355 | * Stream Type:: Receive or send characters. |
| 353 | * Keymap Type:: What function a keystroke invokes. | 356 | * Keymap Type:: What function a keystroke invokes. |
| 354 | * Overlay Type:: How an overlay is represented. | 357 | * Overlay Type:: How an overlay is represented. |
diff --git a/doc/lispref/objects.texi b/doc/lispref/objects.texi index a76fbb1af7f..5e608bcc093 100644 --- a/doc/lispref/objects.texi +++ b/doc/lispref/objects.texi | |||
| @@ -1410,6 +1410,9 @@ editing. | |||
| 1410 | * Window Configuration Type:: Recording the way a frame is subdivided. | 1410 | * Window Configuration Type:: Recording the way a frame is subdivided. |
| 1411 | * Frame Configuration Type:: Recording the status of all frames. | 1411 | * Frame Configuration Type:: Recording the status of all frames. |
| 1412 | * Process Type:: A subprocess of Emacs running on the underlying OS. | 1412 | * Process Type:: A subprocess of Emacs running on the underlying OS. |
| 1413 | * Thread Type:: A thread of Emacs Lisp execution. | ||
| 1414 | * Mutex Type:: An exclusive lock for thread synchronization. | ||
| 1415 | * Condition Variable Type:: Condition variable for thread synchronization. | ||
| 1413 | * Stream Type:: Receive or send characters. | 1416 | * Stream Type:: Receive or send characters. |
| 1414 | * Keymap Type:: What function a keystroke invokes. | 1417 | * Keymap Type:: What function a keystroke invokes. |
| 1415 | * Overlay Type:: How an overlay is represented. | 1418 | * Overlay Type:: How an overlay is represented. |
| @@ -1625,6 +1628,63 @@ giving the name of the process: | |||
| 1625 | return information about, send input or signals to, and receive output | 1628 | return information about, send input or signals to, and receive output |
| 1626 | from processes. | 1629 | from processes. |
| 1627 | 1630 | ||
| 1631 | @node Thread Type | ||
| 1632 | @subsection Thread Type | ||
| 1633 | |||
| 1634 | A @dfn{thread} in Emacs represents a separate thread of Emacs Lisp | ||
| 1635 | execution. It runs its own Lisp program, has its own current buffer, | ||
| 1636 | and can have subprocesses locked to it, i.e.@: subprocesses whose | ||
| 1637 | output only this thread can accept. @xref{Threads}. | ||
| 1638 | |||
| 1639 | Thread objects have no read syntax. They print in hash notation, | ||
| 1640 | giving the name of the thread (if it has been given a name) or its | ||
| 1641 | address in core: | ||
| 1642 | |||
| 1643 | @example | ||
| 1644 | @group | ||
| 1645 | (all-threads) | ||
| 1646 | @result{} (#<thread 0176fc40>) | ||
| 1647 | @end group | ||
| 1648 | @end example | ||
| 1649 | |||
| 1650 | @node Mutex Type | ||
| 1651 | @subsection Mutex Type | ||
| 1652 | |||
| 1653 | A @dfn{mutex} is an exclusive lock that threads can own and disown, | ||
| 1654 | in order to synchronize between them. @xref{Mutexes}. | ||
| 1655 | |||
| 1656 | Mutex objects have no read syntax. They print in hash notation, | ||
| 1657 | giving the name of the mutex (if it has been given a name) or its | ||
| 1658 | address in core: | ||
| 1659 | |||
| 1660 | @example | ||
| 1661 | @group | ||
| 1662 | (make-mutex "my-mutex") | ||
| 1663 | @result{} #<mutex my-mutex> | ||
| 1664 | (make-mutex) | ||
| 1665 | @result{} #<mutex 01c7e4e0> | ||
| 1666 | @end group | ||
| 1667 | @end example | ||
| 1668 | |||
| 1669 | @node Condition Variable Type | ||
| 1670 | @subsection Condition Variable Type | ||
| 1671 | |||
| 1672 | A @dfn{condition variable} is a device for a more complex thread | ||
| 1673 | synchronization than the one supported by a mutex. A thread can wait | ||
| 1674 | on a condition variable, to be woken up when some other thread | ||
| 1675 | notifies the condition. | ||
| 1676 | |||
| 1677 | Condition variable objects have no read syntax. They print in hash | ||
| 1678 | notation, giving the name of the condition variable (if it has been | ||
| 1679 | given a name) or its address in core: | ||
| 1680 | |||
| 1681 | @example | ||
| 1682 | @group | ||
| 1683 | (make-condition-variable (make-mutex)) | ||
| 1684 | @result{} #<condvar 01c45ae8> | ||
| 1685 | @end group | ||
| 1686 | @end example | ||
| 1687 | |||
| 1628 | @node Stream Type | 1688 | @node Stream Type |
| 1629 | @subsection Stream Type | 1689 | @subsection Stream Type |
| 1630 | 1690 | ||
| @@ -1830,6 +1890,9 @@ with references to further information. | |||
| 1830 | @item commandp | 1890 | @item commandp |
| 1831 | @xref{Interactive Call, commandp}. | 1891 | @xref{Interactive Call, commandp}. |
| 1832 | 1892 | ||
| 1893 | @item condition-variable-p | ||
| 1894 | @xref{Condition Variables, condition-variable-p}. | ||
| 1895 | |||
| 1833 | @item consp | 1896 | @item consp |
| 1834 | @xref{List-related Predicates, consp}. | 1897 | @xref{List-related Predicates, consp}. |
| 1835 | 1898 | ||
| @@ -1875,6 +1938,9 @@ with references to further information. | |||
| 1875 | @item markerp | 1938 | @item markerp |
| 1876 | @xref{Predicates on Markers, markerp}. | 1939 | @xref{Predicates on Markers, markerp}. |
| 1877 | 1940 | ||
| 1941 | @item mutexp | ||
| 1942 | @xref{Mutexes, mutexp}. | ||
| 1943 | |||
| 1878 | @item wholenump | 1944 | @item wholenump |
| 1879 | @xref{Predicates on Numbers, wholenump}. | 1945 | @xref{Predicates on Numbers, wholenump}. |
| 1880 | 1946 | ||
| @@ -1908,6 +1974,9 @@ with references to further information. | |||
| 1908 | @item syntax-table-p | 1974 | @item syntax-table-p |
| 1909 | @xref{Syntax Tables, syntax-table-p}. | 1975 | @xref{Syntax Tables, syntax-table-p}. |
| 1910 | 1976 | ||
| 1977 | @item threadp | ||
| 1978 | @xref{Basic Thread Functions, threadp}. | ||
| 1979 | |||
| 1911 | @item vectorp | 1980 | @item vectorp |
| 1912 | @xref{Vectors, vectorp}. | 1981 | @xref{Vectors, vectorp}. |
| 1913 | 1982 | ||
diff --git a/src/lisp.h b/src/lisp.h index 72ea50d5f27..3c7c3dde904 100644 --- a/src/lisp.h +++ b/src/lisp.h | |||
| @@ -845,6 +845,7 @@ enum pvec_type | |||
| 845 | PVEC_THREAD, | 845 | PVEC_THREAD, |
| 846 | PVEC_MUTEX, | 846 | PVEC_MUTEX, |
| 847 | PVEC_CONDVAR, | 847 | PVEC_CONDVAR, |
| 848 | |||
| 848 | /* These should be last, check internal_equal to see why. */ | 849 | /* These should be last, check internal_equal to see why. */ |
| 849 | PVEC_COMPILED, | 850 | PVEC_COMPILED, |
| 850 | PVEC_CHAR_TABLE, | 851 | PVEC_CHAR_TABLE, |
| @@ -3229,6 +3230,7 @@ union specbinding | |||
| 3229 | } bt; | 3230 | } bt; |
| 3230 | }; | 3231 | }; |
| 3231 | 3232 | ||
| 3233 | /* These 3 are defined as macros in thread.h. */ | ||
| 3232 | /* extern union specbinding *specpdl; */ | 3234 | /* extern union specbinding *specpdl; */ |
| 3233 | /* extern union specbinding *specpdl_ptr; */ | 3235 | /* extern union specbinding *specpdl_ptr; */ |
| 3234 | /* extern ptrdiff_t specpdl_size; */ | 3236 | /* extern ptrdiff_t specpdl_size; */ |
diff --git a/src/regex.c b/src/regex.c index e7231d3882b..f1686cf700c 100644 --- a/src/regex.c +++ b/src/regex.c | |||
| @@ -1140,6 +1140,7 @@ print_double_string (re_char *where, re_char *string1, ssize_t size1, | |||
| 1140 | #endif /* not DEBUG */ | 1140 | #endif /* not DEBUG */ |
| 1141 | 1141 | ||
| 1142 | #ifndef emacs | 1142 | #ifndef emacs |
| 1143 | |||
| 1143 | /* Set by `re_set_syntax' to the current regexp syntax to recognize. Can | 1144 | /* Set by `re_set_syntax' to the current regexp syntax to recognize. Can |
| 1144 | also be assigned to arbitrarily: each pattern buffer stores its own | 1145 | also be assigned to arbitrarily: each pattern buffer stores its own |
| 1145 | syntax, so it can be changed between regex compilations. */ | 1146 | syntax, so it can be changed between regex compilations. */ |
diff --git a/src/thread.c b/src/thread.c index dda262984c0..ae2ce3dc02b 100644 --- a/src/thread.c +++ b/src/thread.c | |||
| @@ -144,7 +144,7 @@ static int | |||
| 144 | lisp_mutex_unlock (lisp_mutex_t *mutex) | 144 | lisp_mutex_unlock (lisp_mutex_t *mutex) |
| 145 | { | 145 | { |
| 146 | if (mutex->owner != current_thread) | 146 | if (mutex->owner != current_thread) |
| 147 | error ("blah"); | 147 | error ("Cannot unlock mutex owned by another thread"); |
| 148 | 148 | ||
| 149 | if (--mutex->count > 0) | 149 | if (--mutex->count > 0) |
| 150 | return 0; | 150 | return 0; |
| @@ -301,7 +301,7 @@ finalize_one_mutex (struct Lisp_Mutex *mutex) | |||
| 301 | DEFUN ("make-condition-variable", | 301 | DEFUN ("make-condition-variable", |
| 302 | Fmake_condition_variable, Smake_condition_variable, | 302 | Fmake_condition_variable, Smake_condition_variable, |
| 303 | 1, 2, 0, | 303 | 1, 2, 0, |
| 304 | doc: /* Make a condition variable. | 304 | doc: /* Make a condition variable associated with MUTEX. |
| 305 | A condition variable provides a way for a thread to sleep while | 305 | A condition variable provides a way for a thread to sleep while |
| 306 | waiting for a state change. | 306 | waiting for a state change. |
| 307 | 307 | ||
| @@ -355,27 +355,27 @@ condition_wait_callback (void *arg) | |||
| 355 | } | 355 | } |
| 356 | 356 | ||
| 357 | DEFUN ("condition-wait", Fcondition_wait, Scondition_wait, 1, 1, 0, | 357 | DEFUN ("condition-wait", Fcondition_wait, Scondition_wait, 1, 1, 0, |
| 358 | doc: /* Wait for the condition variable to be notified. | 358 | doc: /* Wait for the condition variable COND to be notified. |
| 359 | CONDITION is the condition variable to wait on. | 359 | COND is the condition variable to wait on. |
| 360 | 360 | ||
| 361 | The mutex associated with CONDITION must be held when this is called. | 361 | The mutex associated with COND must be held when this is called. |
| 362 | It is an error if it is not held. | 362 | It is an error if it is not held. |
| 363 | 363 | ||
| 364 | This releases the mutex and waits for CONDITION to be notified or for | 364 | This releases the mutex and waits for COND to be notified or for |
| 365 | this thread to be signalled with `thread-signal'. When | 365 | this thread to be signalled with `thread-signal'. When |
| 366 | `condition-wait' returns, the mutex will again be locked by this | 366 | `condition-wait' returns, COND's mutex will again be locked by |
| 367 | thread. */) | 367 | this thread. */) |
| 368 | (Lisp_Object condition) | 368 | (Lisp_Object cond) |
| 369 | { | 369 | { |
| 370 | struct Lisp_CondVar *cvar; | 370 | struct Lisp_CondVar *cvar; |
| 371 | struct Lisp_Mutex *mutex; | 371 | struct Lisp_Mutex *mutex; |
| 372 | 372 | ||
| 373 | CHECK_CONDVAR (condition); | 373 | CHECK_CONDVAR (cond); |
| 374 | cvar = XCONDVAR (condition); | 374 | cvar = XCONDVAR (cond); |
| 375 | 375 | ||
| 376 | mutex = XMUTEX (cvar->mutex); | 376 | mutex = XMUTEX (cvar->mutex); |
| 377 | if (!lisp_mutex_owned_p (&mutex->mutex)) | 377 | if (!lisp_mutex_owned_p (&mutex->mutex)) |
| 378 | error ("fixme"); | 378 | error ("Condition variable's mutex is not held by current thread"); |
| 379 | 379 | ||
| 380 | flush_stack_call_func (condition_wait_callback, cvar); | 380 | flush_stack_call_func (condition_wait_callback, cvar); |
| 381 | 381 | ||
| @@ -409,28 +409,28 @@ condition_notify_callback (void *arg) | |||
| 409 | } | 409 | } |
| 410 | 410 | ||
| 411 | DEFUN ("condition-notify", Fcondition_notify, Scondition_notify, 1, 2, 0, | 411 | DEFUN ("condition-notify", Fcondition_notify, Scondition_notify, 1, 2, 0, |
| 412 | doc: /* Notify a condition variable. | 412 | doc: /* Notify COND, a condition variable. |
| 413 | This wakes a thread waiting on CONDITION. | 413 | This wakes a thread waiting on COND. |
| 414 | If ALL is non-nil, all waiting threads are awoken. | 414 | If ALL is non-nil, all waiting threads are awoken. |
| 415 | 415 | ||
| 416 | The mutex associated with CONDITION must be held when this is called. | 416 | The mutex associated with COND must be held when this is called. |
| 417 | It is an error if it is not held. | 417 | It is an error if it is not held. |
| 418 | 418 | ||
| 419 | This releases the mutex when notifying CONDITION. When | 419 | This releases COND's mutex when notifying COND. When |
| 420 | `condition-notify' returns, the mutex will again be locked by this | 420 | `condition-notify' returns, the mutex will again be locked by this |
| 421 | thread. */) | 421 | thread. */) |
| 422 | (Lisp_Object condition, Lisp_Object all) | 422 | (Lisp_Object cond, Lisp_Object all) |
| 423 | { | 423 | { |
| 424 | struct Lisp_CondVar *cvar; | 424 | struct Lisp_CondVar *cvar; |
| 425 | struct Lisp_Mutex *mutex; | 425 | struct Lisp_Mutex *mutex; |
| 426 | struct notify_args args; | 426 | struct notify_args args; |
| 427 | 427 | ||
| 428 | CHECK_CONDVAR (condition); | 428 | CHECK_CONDVAR (cond); |
| 429 | cvar = XCONDVAR (condition); | 429 | cvar = XCONDVAR (cond); |
| 430 | 430 | ||
| 431 | mutex = XMUTEX (cvar->mutex); | 431 | mutex = XMUTEX (cvar->mutex); |
| 432 | if (!lisp_mutex_owned_p (&mutex->mutex)) | 432 | if (!lisp_mutex_owned_p (&mutex->mutex)) |
| 433 | error ("fixme"); | 433 | error ("Condition variable's mutex is not held by current thread"); |
| 434 | 434 | ||
| 435 | args.cvar = cvar; | 435 | args.cvar = cvar; |
| 436 | args.all = !NILP (all); | 436 | args.all = !NILP (all); |
| @@ -440,26 +440,26 @@ thread. */) | |||
| 440 | } | 440 | } |
| 441 | 441 | ||
| 442 | DEFUN ("condition-mutex", Fcondition_mutex, Scondition_mutex, 1, 1, 0, | 442 | DEFUN ("condition-mutex", Fcondition_mutex, Scondition_mutex, 1, 1, 0, |
| 443 | doc: /* Return the mutex associated with CONDITION. */) | 443 | doc: /* Return the mutex associated with condition variable COND. */) |
| 444 | (Lisp_Object condition) | 444 | (Lisp_Object cond) |
| 445 | { | 445 | { |
| 446 | struct Lisp_CondVar *cvar; | 446 | struct Lisp_CondVar *cvar; |
| 447 | 447 | ||
| 448 | CHECK_CONDVAR (condition); | 448 | CHECK_CONDVAR (cond); |
| 449 | cvar = XCONDVAR (condition); | 449 | cvar = XCONDVAR (cond); |
| 450 | 450 | ||
| 451 | return cvar->mutex; | 451 | return cvar->mutex; |
| 452 | } | 452 | } |
| 453 | 453 | ||
| 454 | DEFUN ("condition-name", Fcondition_name, Scondition_name, 1, 1, 0, | 454 | DEFUN ("condition-name", Fcondition_name, Scondition_name, 1, 1, 0, |
| 455 | doc: /* Return the name of CONDITION. | 455 | doc: /* Return the name of condition variable COND. |
| 456 | If no name was given when CONDITION was created, return nil. */) | 456 | If no name was given when COND was created, return nil. */) |
| 457 | (Lisp_Object condition) | 457 | (Lisp_Object cond) |
| 458 | { | 458 | { |
| 459 | struct Lisp_CondVar *cvar; | 459 | struct Lisp_CondVar *cvar; |
| 460 | 460 | ||
| 461 | CHECK_CONDVAR (condition); | 461 | CHECK_CONDVAR (cond); |
| 462 | cvar = XCONDVAR (condition); | 462 | cvar = XCONDVAR (cond); |
| 463 | 463 | ||
| 464 | return cvar->name; | 464 | return cvar->name; |
| 465 | } | 465 | } |
| @@ -540,7 +540,7 @@ mark_one_thread (struct thread_state *thread) | |||
| 540 | 540 | ||
| 541 | mark_object (thread->m_last_thing_searched); | 541 | mark_object (thread->m_last_thing_searched); |
| 542 | 542 | ||
| 543 | if (thread->m_saved_last_thing_searched) | 543 | if (!NILP (thread->m_saved_last_thing_searched)) |
| 544 | mark_object (thread->m_saved_last_thing_searched); | 544 | mark_object (thread->m_saved_last_thing_searched); |
| 545 | } | 545 | } |
| 546 | 546 | ||
| @@ -678,7 +678,7 @@ finalize_one_thread (struct thread_state *state) | |||
| 678 | DEFUN ("make-thread", Fmake_thread, Smake_thread, 1, 2, 0, | 678 | DEFUN ("make-thread", Fmake_thread, Smake_thread, 1, 2, 0, |
| 679 | doc: /* Start a new thread and run FUNCTION in it. | 679 | doc: /* Start a new thread and run FUNCTION in it. |
| 680 | When the function exits, the thread dies. | 680 | When the function exits, the thread dies. |
| 681 | If NAME is given, it names the new thread. */) | 681 | If NAME is given, it must be a string; it names the new thread. */) |
| 682 | (Lisp_Object function, Lisp_Object name) | 682 | (Lisp_Object function, Lisp_Object name) |
| 683 | { | 683 | { |
| 684 | sys_thread_t thr; | 684 | sys_thread_t thr; |
| @@ -843,8 +843,9 @@ thread_join_callback (void *arg) | |||
| 843 | } | 843 | } |
| 844 | 844 | ||
| 845 | DEFUN ("thread-join", Fthread_join, Sthread_join, 1, 1, 0, | 845 | DEFUN ("thread-join", Fthread_join, Sthread_join, 1, 1, 0, |
| 846 | doc: /* Wait for a thread to exit. | 846 | doc: /* Wait for THREAD to exit. |
| 847 | This blocks the current thread until THREAD exits. | 847 | This blocks the current thread until THREAD exits or until |
| 848 | the current thread is signaled. | ||
| 848 | It is an error for a thread to try to join itself. */) | 849 | It is an error for a thread to try to join itself. */) |
| 849 | (Lisp_Object thread) | 850 | (Lisp_Object thread) |
| 850 | { | 851 | { |
| @@ -854,7 +855,7 @@ It is an error for a thread to try to join itself. */) | |||
| 854 | tstate = XTHREAD (thread); | 855 | tstate = XTHREAD (thread); |
| 855 | 856 | ||
| 856 | if (tstate == current_thread) | 857 | if (tstate == current_thread) |
| 857 | error ("cannot join current thread"); | 858 | error ("Cannot join current thread"); |
| 858 | 859 | ||
| 859 | if (thread_alive_p (tstate)) | 860 | if (thread_alive_p (tstate)) |
| 860 | flush_stack_call_func (thread_join_callback, tstate); | 861 | flush_stack_call_func (thread_join_callback, tstate); |
| @@ -863,7 +864,7 @@ It is an error for a thread to try to join itself. */) | |||
| 863 | } | 864 | } |
| 864 | 865 | ||
| 865 | DEFUN ("all-threads", Fall_threads, Sall_threads, 0, 0, 0, | 866 | DEFUN ("all-threads", Fall_threads, Sall_threads, 0, 0, 0, |
| 866 | doc: /* Return a list of all threads. */) | 867 | doc: /* Return a list of all the live threads. */) |
| 867 | (void) | 868 | (void) |
| 868 | { | 869 | { |
| 869 | Lisp_Object result = Qnil; | 870 | Lisp_Object result = Qnil; |
diff --git a/src/xgselect.c b/src/xgselect.c index e418e1a3c4e..2f23764ae41 100644 --- a/src/xgselect.c +++ b/src/xgselect.c | |||
| @@ -76,6 +76,9 @@ xg_select (int fds_lim, fd_set *rfds, fd_set *wfds, fd_set *efds, | |||
| 76 | 76 | ||
| 77 | if (gfds_size < n_gfds) | 77 | if (gfds_size < n_gfds) |
| 78 | { | 78 | { |
| 79 | /* Avoid using SAFE_NALLOCA, as that implicitly refers to the | ||
| 80 | current thread. Using xnmalloc avoids thread-switching | ||
| 81 | problems here. */ | ||
| 79 | gfds = xnmalloc (n_gfds, sizeof *gfds); | 82 | gfds = xnmalloc (n_gfds, sizeof *gfds); |
| 80 | must_free = 1; | 83 | must_free = 1; |
| 81 | gfds_size = n_gfds; | 84 | gfds_size = n_gfds; |