aboutsummaryrefslogtreecommitdiffstats
path: root/test/src
diff options
context:
space:
mode:
authorEli Zaretskii2016-12-10 18:54:43 +0200
committerEli Zaretskii2016-12-10 18:54:43 +0200
commit2412a1fc05fe9f89b171d0781c2d530923f48adc (patch)
treed42a5d2608e65a10b1cc23c6b4609d54bef25d49 /test/src
parentfc0fd24c105bde4c001ebebe4b8b7e1f96cd2871 (diff)
parent828b4560cd4a0d8cb9b7a7a3e20ff0c53ba86cfa (diff)
downloademacs-2412a1fc05fe9f89b171d0781c2d530923f48adc.tar.gz
emacs-2412a1fc05fe9f89b171d0781c2d530923f48adc.zip
Support concurrency in Emacs Lisp
Merge branch 'test-concurrency' * src/thread.c: * src/thread.h: * src/systhread.c: * src/systhread.h: New files. * src/xgselect.c (xg_select): Avoid using SAFE_NALLOCA and use xnmalloc unconditionally. * src/window.c (struct save_window_data): Rename current_buffer to f_current_buffer. * src/w32proc.c (sys_select): Change the function signature to closer fit 'pselect' on Posix hosts. * src/search.c: * src/regex.h: Convert some globals to macros that reference thread-specific values. * src/process.c (pset_thread, add_non_keyboard_read_fd) (add_process_read_fd, add_non_blocking_write_fd) (recompute_input_desc, compute_input_wait_mask) (compute_non_process_wait_mask, compute_non_keyboard_wait_mask) (compute_write_mask, clear_waiting_thread_info) (update_processes_for_thread_death, Fset_process_thread) (Fprocess_thread): New functions. (enum fd_bits): New enumeration. (fd_callback_data): Add 'thread' and 'waiting_thread', rename 'condition' to 'flags'. (set_process_filter_masks, create_process, create_pty) (Fmake_serial_process, finish_after_tls_connection) (connect_network_socket, deactivate_process) (server_accept_connection, wait_reading_process_output) (Fcontinue_process, Fstop_process, keyboard_bit_set) (add_timer_wait_descriptor, add_keyboard_wait_descriptor) (delete_keyboard_wait_descriptor): Use the new functions instead of manipulating fd flags and masks directly. (syms_of_process): Defsubr the new primitives. * src/print.c (print_object): Print threads, mutexes, and conditional variables. * src/lisp.h (enum pvec_type): New values PVEC_THREAD, PVEC_MUTEX, and PVEC_CONDVAR. (XTHREAD, XMUTEX, XCONDVAR, THREADP, MUTEXP, CONDVARP) (CHECK_THREAD, CHECK_MUTEX, CHECK_CONDVAR): New inline functions. (XSETTHREAD, XSETMUTEX, XSETCONDVAR): New macros. (struct handler): Add back byte_stack. Rename lisp_eval_depth to f_lisp_eval_depth. * src/eval.c (specpdl_kind, specpdl_arg, do_specbind) (rebind_for_thread_switch, do_one_unbind) (unbind_for_thread_switch): New functions. (init_eval): 'handlerlist' is not malloc'ed. (specbind): Call do_specbind. (unbind_to): Call do_one_unbind. (mark_specpdl): Accept 2 arguments. (mark_specpdl): Mark the saved value in a let-binding. * src/emacs.c (main): Call init_threads_once, init_threads, and syms_of_threads. * src/data.c (Ftype_of): Support thread, mutex, and condvar objects. (Fthreadp, Fmutexp, Fcondition_variable_p): New functions. (syms_of_data): DEFSYM and defsubr new symbols and primitives. * src/bytecode.c (struct byte_stack, FETCH, CHECK_RANGE) (BYTE_CODE_QUIT): Add back. (exec_byte_code): Add back byte stack manipulation. * src/alloc.c (cleanup_vector): Handle threads, mutexes, and conditional variables. (mark_stack): Now extern; accept additional argument 'bottom'. (flush_stack_call_func): New function. (garbage_collect_1): Call mark_threads and unmark_threads. Don't mark handlers. * src/.gdbinit (xbytecode): Add back. * test/src/thread-tests.el: New tests. * test/src/data-tests.el (binding-test-manual) (binding-test-setq-default, binding-test-makunbound) (binding-test-defvar-bool, binding-test-defvar-int) (binding-test-set-constant-t, binding-test-set-constant-nil) (binding-test-set-constant-keyword) (binding-test-set-constant-nil): New tests. * doc/lispref/processes.texi (Processes and Threads): New subsection. * doc/lispref/threads.texi: New file * doc/lispref/elisp.texi (Top): Include it. * doc/lispref/objects.texi (Thread Type, Mutex Type) (Condition Variable Type): New subsections. (Type Predicates): Add thread-related predicates. * doc/lispref/objects.texi (Editing Types): * doc/lispref/elisp.texi (Top): Update higher-level menus. * etc/NEWS: Mention concurrency features.
Diffstat (limited to 'test/src')
-rw-r--r--test/src/data-tests.el81
-rw-r--r--test/src/thread-tests.el213
2 files changed, 294 insertions, 0 deletions
diff --git a/test/src/data-tests.el b/test/src/data-tests.el
index 4c2ea54862c..de0b8e68321 100644
--- a/test/src/data-tests.el
+++ b/test/src/data-tests.el
@@ -256,6 +256,87 @@ comparing the subr with a much slower lisp implementation."
256 (v3 (bool-vector-not v1))) 256 (v3 (bool-vector-not v1)))
257 (should (equal v2 v3)))) 257 (should (equal v2 v3))))
258 258
259;; Tests for variable bindings
260
261(defvar binding-test-buffer-A (get-buffer-create "A"))
262(defvar binding-test-buffer-B (get-buffer-create "B"))
263
264(defvar binding-test-always-local 'always)
265(make-variable-buffer-local 'binding-test-always-local)
266
267(defvar binding-test-some-local 'some)
268(with-current-buffer binding-test-buffer-A
269 (set (make-local-variable 'binding-test-some-local) 'local))
270
271(ert-deftest binding-test-manual ()
272 "A test case from the elisp manual."
273 (save-excursion
274 (set-buffer binding-test-buffer-A)
275 (let ((binding-test-some-local 'something-else))
276 (should (eq binding-test-some-local 'something-else))
277 (set-buffer binding-test-buffer-B)
278 (should (eq binding-test-some-local 'some)))
279 (should (eq binding-test-some-local 'some))
280 (set-buffer binding-test-buffer-A)
281 (should (eq binding-test-some-local 'local))))
282
283(ert-deftest binding-test-setq-default ()
284 "Test that a setq-default has no effect when there is a local binding."
285 (save-excursion
286 (set-buffer binding-test-buffer-B)
287 ;; This variable is not local in this buffer.
288 (let ((binding-test-some-local 'something-else))
289 (setq-default binding-test-some-local 'new-default))
290 (should (eq binding-test-some-local 'some))))
291
292(ert-deftest binding-test-makunbound ()
293 "Tests of makunbound, from the manual."
294 (save-excursion
295 (set-buffer binding-test-buffer-B)
296 (should (boundp 'binding-test-some-local))
297 (let ((binding-test-some-local 'outer))
298 (let ((binding-test-some-local 'inner))
299 (makunbound 'binding-test-some-local)
300 (should (not (boundp 'binding-test-some-local))))
301 (should (and (boundp 'binding-test-some-local)
302 (eq binding-test-some-local 'outer))))))
303
304(ert-deftest binding-test-defvar-bool ()
305 "Test DEFVAR_BOOL"
306 (let ((display-hourglass 5))
307 (should (eq display-hourglass t))))
308
309(ert-deftest binding-test-defvar-int ()
310 "Test DEFVAR_INT"
311 (should-error (setq gc-cons-threshold 5.0) :type 'wrong-type-argument))
312
313(ert-deftest binding-test-set-constant-t ()
314 "Test setting the constant t"
315 (should-error (setq t 'bob) :type 'setting-constant))
316
317(ert-deftest binding-test-set-constant-nil ()
318 "Test setting the constant nil"
319 (should-error (setq nil 'bob) :type 'setting-constant))
320
321(ert-deftest binding-test-set-constant-keyword ()
322 "Test setting a keyword constant"
323 (should-error (setq :keyword 'bob) :type 'setting-constant))
324
325(ert-deftest binding-test-set-constant-nil ()
326 "Test setting a keyword to itself"
327 (should (setq :keyword :keyword)))
328
329;; More tests to write -
330;; kill-local-variable
331;; defconst; can modify
332;; defvar and defconst modify the local binding [ doesn't matter for us ]
333;; various kinds of special internal forwarding objects
334;; a couple examples in manual, not enough
335;; frame-local vars
336;; variable aliases
337
338;; Tests for watchpoints
339
259(ert-deftest data-tests-variable-watchers () 340(ert-deftest data-tests-variable-watchers ()
260 (defvar data-tests-var 0) 341 (defvar data-tests-var 0)
261 (let* ((watch-data nil) 342 (let* ((watch-data nil)
diff --git a/test/src/thread-tests.el b/test/src/thread-tests.el
new file mode 100644
index 00000000000..c65b6425c3c
--- /dev/null
+++ b/test/src/thread-tests.el
@@ -0,0 +1,213 @@
1;;; threads.el --- tests for threads.
2
3;; Copyright (C) 2012, 2013 Free Software Foundation, Inc.
4
5;; This file is part of GNU Emacs.
6
7;; GNU Emacs is free software: you can redistribute it and/or modify
8;; it under the terms of the GNU General Public License as published by
9;; the Free Software Foundation, either version 3 of the License, or
10;; (at your option) any later version.
11
12;; GNU Emacs is distributed in the hope that it will be useful,
13;; but WITHOUT ANY WARRANTY; without even the implied warranty of
14;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15;; GNU General Public License for more details.
16
17;; You should have received a copy of the GNU General Public License
18;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
19
20;;; Code:
21
22(ert-deftest threads-is-one ()
23 "test for existence of a thread"
24 (should (current-thread)))
25
26(ert-deftest threads-threadp ()
27 "test of threadp"
28 (should (threadp (current-thread))))
29
30(ert-deftest threads-type ()
31 "test of thread type"
32 (should (eq (type-of (current-thread)) 'thread)))
33
34(ert-deftest threads-name ()
35 "test for name of a thread"
36 (should
37 (string= "hi bob" (thread-name (make-thread #'ignore "hi bob")))))
38
39(ert-deftest threads-alive ()
40 "test for thread liveness"
41 (should
42 (thread-alive-p (make-thread #'ignore))))
43
44(ert-deftest threads-all-threads ()
45 "simple test for all-threads"
46 (should (listp (all-threads))))
47
48(defvar threads-test-global nil)
49
50(defun threads-test-thread1 ()
51 (setq threads-test-global 23))
52
53(ert-deftest threads-basic ()
54 "basic thread test"
55 (should
56 (progn
57 (setq threads-test-global nil)
58 (make-thread #'threads-test-thread1)
59 (while (not threads-test-global)
60 (thread-yield))
61 threads-test-global)))
62
63(ert-deftest threads-join ()
64 "test of thread-join"
65 (should
66 (progn
67 (setq threads-test-global nil)
68 (let ((thread (make-thread #'threads-test-thread1)))
69 (thread-join thread)
70 (and threads-test-global
71 (not (thread-alive-p thread)))))))
72
73(ert-deftest threads-join-self ()
74 "cannot thread-join the current thread"
75 (should-error (thread-join (current-thread))))
76
77(defvar threads-test-binding nil)
78
79(defun threads-test-thread2 ()
80 (let ((threads-test-binding 23))
81 (thread-yield))
82 (setq threads-test-global 23))
83
84(ert-deftest threads-let-binding ()
85 "simple test of threads and let bindings"
86 (should
87 (progn
88 (setq threads-test-global nil)
89 (make-thread #'threads-test-thread2)
90 (while (not threads-test-global)
91 (thread-yield))
92 (and (not threads-test-binding)
93 threads-test-global))))
94
95(ert-deftest threads-mutexp ()
96 "simple test of mutexp"
97 (should-not (mutexp 'hi)))
98
99(ert-deftest threads-mutexp-2 ()
100 "another simple test of mutexp"
101 (should (mutexp (make-mutex))))
102
103(ert-deftest threads-mutex-type ()
104 "type-of mutex"
105 (should (eq (type-of (make-mutex)) 'mutex)))
106
107(ert-deftest threads-mutex-lock-unlock ()
108 "test mutex-lock and unlock"
109 (should
110 (let ((mx (make-mutex)))
111 (mutex-lock mx)
112 (mutex-unlock mx)
113 t)))
114
115(ert-deftest threads-mutex-recursive ()
116 "test mutex-lock and unlock"
117 (should
118 (let ((mx (make-mutex)))
119 (mutex-lock mx)
120 (mutex-lock mx)
121 (mutex-unlock mx)
122 (mutex-unlock mx)
123 t)))
124
125(defvar threads-mutex nil)
126(defvar threads-mutex-key nil)
127
128(defun threads-test-mlock ()
129 (mutex-lock threads-mutex)
130 (setq threads-mutex-key 23)
131 (while threads-mutex-key
132 (thread-yield))
133 (mutex-unlock threads-mutex))
134
135(ert-deftest threads-mutex-contention ()
136 "test of mutex contention"
137 (should
138 (progn
139 (setq threads-mutex (make-mutex))
140 (setq threads-mutex-key nil)
141 (make-thread #'threads-test-mlock)
142 ;; Wait for other thread to get the lock.
143 (while (not threads-mutex-key)
144 (thread-yield))
145 ;; Try now.
146 (setq threads-mutex-key nil)
147 (mutex-lock threads-mutex)
148 (mutex-unlock threads-mutex)
149 t)))
150
151(defun threads-test-mlock2 ()
152 (setq threads-mutex-key 23)
153 (mutex-lock threads-mutex))
154
155(ert-deftest threads-mutex-signal ()
156 "test signalling a blocked thread"
157 (should
158 (progn
159 (setq threads-mutex (make-mutex))
160 (setq threads-mutex-key nil)
161 (mutex-lock threads-mutex)
162 (let ((thr (make-thread #'threads-test-mlock2)))
163 (while (not threads-mutex-key)
164 (thread-yield))
165 (thread-signal thr 'quit nil)
166 (thread-join thr))
167 t)))
168
169(defun threads-test-io-switch ()
170 (setq threads-test-global 23))
171
172(ert-deftest threads-io-switch ()
173 "test that accept-process-output causes thread switch"
174 (should
175 (progn
176 (setq threads-test-global nil)
177 (make-thread #'threads-test-io-switch)
178 (while (not threads-test-global)
179 (accept-process-output nil 1))
180 threads-test-global)))
181
182(ert-deftest threads-condvarp ()
183 "simple test of condition-variable-p"
184 (should-not (condition-variable-p 'hi)))
185
186(ert-deftest threads-condvarp-2 ()
187 "another simple test of condition-variable-p"
188 (should (condition-variable-p (make-condition-variable (make-mutex)))))
189
190(ert-deftest threads-condvar-type ()
191 "type-of condvar"
192 (should (eq (type-of (make-condition-variable (make-mutex)))
193 'condition-variable)))
194
195(ert-deftest threads-condvar-mutex ()
196 "simple test of condition-mutex"
197 (should
198 (let ((m (make-mutex)))
199 (eq m (condition-mutex (make-condition-variable m))))))
200
201(ert-deftest threads-condvar-name ()
202 "simple test of condition-name"
203 (should
204 (eq nil (condition-name (make-condition-variable (make-mutex))))))
205
206(ert-deftest threads-condvar-name-2 ()
207 "another simple test of condition-name"
208 (should
209 (string= "hi bob"
210 (condition-name (make-condition-variable (make-mutex)
211 "hi bob")))))
212
213;;; threads.el ends here