diff options
| author | Eli Zaretskii | 2016-12-10 18:54:43 +0200 |
|---|---|---|
| committer | Eli Zaretskii | 2016-12-10 18:54:43 +0200 |
| commit | 2412a1fc05fe9f89b171d0781c2d530923f48adc (patch) | |
| tree | d42a5d2608e65a10b1cc23c6b4609d54bef25d49 /src/bytecode.c | |
| parent | fc0fd24c105bde4c001ebebe4b8b7e1f96cd2871 (diff) | |
| parent | 828b4560cd4a0d8cb9b7a7a3e20ff0c53ba86cfa (diff) | |
| download | emacs-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 'src/bytecode.c')
| -rw-r--r-- | src/bytecode.c | 203 |
1 files changed, 155 insertions, 48 deletions
diff --git a/src/bytecode.c b/src/bytecode.c index 71ecdbf2cc0..c581ed6d982 100644 --- a/src/bytecode.c +++ b/src/bytecode.c | |||
| @@ -280,10 +280,68 @@ enum byte_code_op | |||
| 280 | Bset_mark = 0163, /* this loser is no longer generated as of v18 */ | 280 | Bset_mark = 0163, /* this loser is no longer generated as of v18 */ |
| 281 | #endif | 281 | #endif |
| 282 | }; | 282 | }; |
| 283 | |||
| 284 | /* Whether to maintain a `top' and `bottom' field in the stack frame. */ | ||
| 285 | #define BYTE_MAINTAIN_TOP BYTE_CODE_SAFE | ||
| 283 | 286 | ||
| 284 | /* Fetch the next byte from the bytecode stream. */ | 287 | /* Structure describing a value stack used during byte-code execution |
| 288 | in Fbyte_code. */ | ||
| 289 | |||
| 290 | struct byte_stack | ||
| 291 | { | ||
| 292 | /* Program counter. This points into the byte_string below | ||
| 293 | and is relocated when that string is relocated. */ | ||
| 294 | const unsigned char *pc; | ||
| 295 | |||
| 296 | /* Top and bottom of stack. The bottom points to an area of memory | ||
| 297 | allocated with alloca in Fbyte_code. */ | ||
| 298 | #if BYTE_MAINTAIN_TOP | ||
| 299 | Lisp_Object *top, *bottom; | ||
| 300 | #endif | ||
| 301 | |||
| 302 | /* The string containing the byte-code, and its current address. | ||
| 303 | Storing this here protects it from GC because mark_byte_stack | ||
| 304 | marks it. */ | ||
| 305 | Lisp_Object byte_string; | ||
| 306 | const unsigned char *byte_string_start; | ||
| 307 | |||
| 308 | /* Next entry in byte_stack_list. */ | ||
| 309 | struct byte_stack *next; | ||
| 310 | }; | ||
| 311 | |||
| 312 | /* A list of currently active byte-code execution value stacks. | ||
| 313 | Fbyte_code adds an entry to the head of this list before it starts | ||
| 314 | processing byte-code, and it removes the entry again when it is | ||
| 315 | done. Signaling an error truncates the list. | ||
| 316 | |||
| 317 | byte_stack_list is a macro defined in thread.h. */ | ||
| 318 | /* struct byte_stack *byte_stack_list; */ | ||
| 319 | |||
| 320 | |||
| 321 | /* Relocate program counters in the stacks on byte_stack_list. Called | ||
| 322 | when GC has completed. */ | ||
| 323 | |||
| 324 | void | ||
| 325 | relocate_byte_stack (struct byte_stack *stack) | ||
| 326 | { | ||
| 327 | for (; stack; stack = stack->next) | ||
| 328 | { | ||
| 329 | if (stack->byte_string_start != SDATA (stack->byte_string)) | ||
| 330 | { | ||
| 331 | ptrdiff_t offset = stack->pc - stack->byte_string_start; | ||
| 332 | stack->byte_string_start = SDATA (stack->byte_string); | ||
| 333 | stack->pc = stack->byte_string_start + offset; | ||
| 334 | } | ||
| 335 | } | ||
| 336 | } | ||
| 285 | 337 | ||
| 286 | #define FETCH (*pc++) | 338 | |
| 339 | /* Fetch the next byte from the bytecode stream. */ | ||
| 340 | #ifdef BYTE_CODE_SAFE | ||
| 341 | #define FETCH (eassert (stack.byte_string_start == SDATA (stack.byte_string)), *stack.pc++) | ||
| 342 | #else | ||
| 343 | #define FETCH *stack.pc++ | ||
| 344 | #endif | ||
| 287 | 345 | ||
| 288 | /* Fetch two bytes from the bytecode stream and make a 16-bit number | 346 | /* Fetch two bytes from the bytecode stream and make a 16-bit number |
| 289 | out of them. */ | 347 | out of them. */ |
| @@ -308,6 +366,29 @@ enum byte_code_op | |||
| 308 | 366 | ||
| 309 | #define TOP (*top) | 367 | #define TOP (*top) |
| 310 | 368 | ||
| 369 | #define CHECK_RANGE(ARG) \ | ||
| 370 | (BYTE_CODE_SAFE && bytestr_length <= (ARG) ? emacs_abort () : (void) 0) | ||
| 371 | |||
| 372 | /* A version of the QUIT macro which makes sure that the stack top is | ||
| 373 | set before signaling `quit'. */ | ||
| 374 | #define BYTE_CODE_QUIT \ | ||
| 375 | do { \ | ||
| 376 | if (quitcounter++) \ | ||
| 377 | break; \ | ||
| 378 | maybe_gc (); \ | ||
| 379 | if (!NILP (Vquit_flag) && NILP (Vinhibit_quit)) \ | ||
| 380 | { \ | ||
| 381 | Lisp_Object flag = Vquit_flag; \ | ||
| 382 | Vquit_flag = Qnil; \ | ||
| 383 | if (EQ (Vthrow_on_input, flag)) \ | ||
| 384 | Fthrow (Vthrow_on_input, Qt); \ | ||
| 385 | quit (); \ | ||
| 386 | } \ | ||
| 387 | else if (pending_signals) \ | ||
| 388 | process_pending_signals (); \ | ||
| 389 | } while (0) | ||
| 390 | |||
| 391 | |||
| 311 | DEFUN ("byte-code", Fbyte_code, Sbyte_code, 3, 3, 0, | 392 | DEFUN ("byte-code", Fbyte_code, Sbyte_code, 3, 3, 0, |
| 312 | doc: /* Function used internally in byte-compiled code. | 393 | doc: /* Function used internally in byte-compiled code. |
| 313 | The first argument, BYTESTR, is a string of byte code; | 394 | The first argument, BYTESTR, is a string of byte code; |
| @@ -357,18 +438,19 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, | |||
| 357 | 438 | ||
| 358 | ptrdiff_t bytestr_length = SBYTES (bytestr); | 439 | ptrdiff_t bytestr_length = SBYTES (bytestr); |
| 359 | Lisp_Object *vectorp = XVECTOR (vector)->contents; | 440 | Lisp_Object *vectorp = XVECTOR (vector)->contents; |
| 441 | struct byte_stack stack; | ||
| 360 | 442 | ||
| 361 | unsigned char quitcounter = 1; | 443 | stack.byte_string = bytestr; |
| 444 | stack.pc = stack.byte_string_start = SDATA (bytestr); | ||
| 445 | unsigned char quitcounter = 0; | ||
| 362 | EMACS_INT stack_items = XFASTINT (maxdepth) + 1; | 446 | EMACS_INT stack_items = XFASTINT (maxdepth) + 1; |
| 363 | USE_SAFE_ALLOCA; | 447 | USE_SAFE_ALLOCA; |
| 364 | Lisp_Object *stack_base; | 448 | Lisp_Object *stack_base; |
| 365 | SAFE_ALLOCA_LISP_EXTRA (stack_base, stack_items, bytestr_length); | 449 | SAFE_ALLOCA_LISP (stack_base, stack_items); |
| 366 | Lisp_Object *stack_lim = stack_base + stack_items; | 450 | Lisp_Object *stack_lim = stack_base + stack_items; |
| 367 | Lisp_Object *top = stack_base; | 451 | Lisp_Object *top = stack_base; |
| 368 | memcpy (stack_lim, SDATA (bytestr), bytestr_length); | 452 | stack.next = byte_stack_list; |
| 369 | void *void_stack_lim = stack_lim; | 453 | byte_stack_list = &stack; |
| 370 | unsigned char const *bytestr_data = void_stack_lim; | ||
| 371 | unsigned char const *pc = bytestr_data; | ||
| 372 | ptrdiff_t count = SPECPDL_INDEX (); | 454 | ptrdiff_t count = SPECPDL_INDEX (); |
| 373 | 455 | ||
| 374 | if (!NILP (args_template)) | 456 | if (!NILP (args_template)) |
| @@ -508,10 +590,15 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, | |||
| 508 | 590 | ||
| 509 | CASE (Bgotoifnil): | 591 | CASE (Bgotoifnil): |
| 510 | { | 592 | { |
| 511 | Lisp_Object v1 = POP; | 593 | Lisp_Object v1; |
| 512 | op = FETCH2; | 594 | op = FETCH2; |
| 595 | v1 = POP; | ||
| 513 | if (NILP (v1)) | 596 | if (NILP (v1)) |
| 514 | goto op_branch; | 597 | { |
| 598 | BYTE_CODE_QUIT; | ||
| 599 | CHECK_RANGE (op); | ||
| 600 | stack.pc = stack.byte_string_start + op; | ||
| 601 | } | ||
| 515 | NEXT; | 602 | NEXT; |
| 516 | } | 603 | } |
| 517 | 604 | ||
| @@ -569,7 +656,7 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, | |||
| 569 | if (SYMBOLP (sym) | 656 | if (SYMBOLP (sym) |
| 570 | && !EQ (val, Qunbound) | 657 | && !EQ (val, Qunbound) |
| 571 | && !XSYMBOL (sym)->redirect | 658 | && !XSYMBOL (sym)->redirect |
| 572 | && !SYMBOL_TRAPPED_WRITE_P (sym)) | 659 | && !SYMBOL_TRAPPED_WRITE_P (sym)) |
| 573 | SET_SYMBOL_VAL (XSYMBOL (sym), val); | 660 | SET_SYMBOL_VAL (XSYMBOL (sym), val); |
| 574 | else | 661 | else |
| 575 | set_internal (sym, val, Qnil, SET_INTERNAL_SET); | 662 | set_internal (sym, val, Qnil, SET_INTERNAL_SET); |
| @@ -666,72 +753,86 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, | |||
| 666 | NEXT; | 753 | NEXT; |
| 667 | 754 | ||
| 668 | CASE (Bgoto): | 755 | CASE (Bgoto): |
| 669 | op = FETCH2; | 756 | BYTE_CODE_QUIT; |
| 670 | op_branch: | 757 | op = FETCH2; /* pc = FETCH2 loses since FETCH2 contains pc++ */ |
| 671 | op -= pc - bytestr_data; | 758 | CHECK_RANGE (op); |
| 672 | op_relative_branch: | 759 | stack.pc = stack.byte_string_start + op; |
| 673 | if (BYTE_CODE_SAFE | ||
| 674 | && ! (bytestr_data - pc <= op | ||
| 675 | && op < bytestr_data + bytestr_length - pc)) | ||
| 676 | emacs_abort (); | ||
| 677 | quitcounter += op < 0; | ||
| 678 | if (!quitcounter) | ||
| 679 | { | ||
| 680 | quitcounter = 1; | ||
| 681 | maybe_gc (); | ||
| 682 | QUIT; | ||
| 683 | } | ||
| 684 | pc += op; | ||
| 685 | NEXT; | 760 | NEXT; |
| 686 | 761 | ||
| 687 | CASE (Bgotoifnonnil): | 762 | CASE (Bgotoifnonnil): |
| 688 | op = FETCH2; | 763 | op = FETCH2; |
| 689 | if (!NILP (POP)) | 764 | Lisp_Object v1 = POP; |
| 690 | goto op_branch; | 765 | if (!NILP (v1)) |
| 766 | { | ||
| 767 | BYTE_CODE_QUIT; | ||
| 768 | CHECK_RANGE (op); | ||
| 769 | stack.pc = stack.byte_string_start + op; | ||
| 770 | } | ||
| 691 | NEXT; | 771 | NEXT; |
| 692 | 772 | ||
| 693 | CASE (Bgotoifnilelsepop): | 773 | CASE (Bgotoifnilelsepop): |
| 694 | op = FETCH2; | 774 | op = FETCH2; |
| 695 | if (NILP (TOP)) | 775 | if (NILP (TOP)) |
| 696 | goto op_branch; | 776 | { |
| 697 | DISCARD (1); | 777 | BYTE_CODE_QUIT; |
| 778 | CHECK_RANGE (op); | ||
| 779 | stack.pc = stack.byte_string_start + op; | ||
| 780 | } | ||
| 781 | else DISCARD (1); | ||
| 698 | NEXT; | 782 | NEXT; |
| 699 | 783 | ||
| 700 | CASE (Bgotoifnonnilelsepop): | 784 | CASE (Bgotoifnonnilelsepop): |
| 701 | op = FETCH2; | 785 | op = FETCH2; |
| 702 | if (!NILP (TOP)) | 786 | if (!NILP (TOP)) |
| 703 | goto op_branch; | 787 | { |
| 704 | DISCARD (1); | 788 | BYTE_CODE_QUIT; |
| 789 | CHECK_RANGE (op); | ||
| 790 | stack.pc = stack.byte_string_start + op; | ||
| 791 | } | ||
| 792 | else DISCARD (1); | ||
| 705 | NEXT; | 793 | NEXT; |
| 706 | 794 | ||
| 707 | CASE (BRgoto): | 795 | CASE (BRgoto): |
| 708 | op = FETCH - 128; | 796 | BYTE_CODE_QUIT; |
| 709 | goto op_relative_branch; | 797 | stack.pc += (int) *stack.pc - 127; |
| 798 | NEXT; | ||
| 710 | 799 | ||
| 711 | CASE (BRgotoifnil): | 800 | CASE (BRgotoifnil): |
| 712 | op = FETCH - 128; | ||
| 713 | if (NILP (POP)) | 801 | if (NILP (POP)) |
| 714 | goto op_relative_branch; | 802 | { |
| 803 | BYTE_CODE_QUIT; | ||
| 804 | stack.pc += (int) *stack.pc - 128; | ||
| 805 | } | ||
| 806 | stack.pc++; | ||
| 715 | NEXT; | 807 | NEXT; |
| 716 | 808 | ||
| 717 | CASE (BRgotoifnonnil): | 809 | CASE (BRgotoifnonnil): |
| 718 | op = FETCH - 128; | ||
| 719 | if (!NILP (POP)) | 810 | if (!NILP (POP)) |
| 720 | goto op_relative_branch; | 811 | { |
| 812 | BYTE_CODE_QUIT; | ||
| 813 | stack.pc += (int) *stack.pc - 128; | ||
| 814 | } | ||
| 815 | stack.pc++; | ||
| 721 | NEXT; | 816 | NEXT; |
| 722 | 817 | ||
| 723 | CASE (BRgotoifnilelsepop): | 818 | CASE (BRgotoifnilelsepop): |
| 724 | op = FETCH - 128; | 819 | op = *stack.pc++; |
| 725 | if (NILP (TOP)) | 820 | if (NILP (TOP)) |
| 726 | goto op_relative_branch; | 821 | { |
| 727 | DISCARD (1); | 822 | BYTE_CODE_QUIT; |
| 823 | stack.pc += op - 128; | ||
| 824 | } | ||
| 825 | else DISCARD (1); | ||
| 728 | NEXT; | 826 | NEXT; |
| 729 | 827 | ||
| 730 | CASE (BRgotoifnonnilelsepop): | 828 | CASE (BRgotoifnonnilelsepop): |
| 731 | op = FETCH - 128; | 829 | op = *stack.pc++; |
| 732 | if (!NILP (TOP)) | 830 | if (!NILP (TOP)) |
| 733 | goto op_relative_branch; | 831 | { |
| 734 | DISCARD (1); | 832 | BYTE_CODE_QUIT; |
| 833 | stack.pc += op - 128; | ||
| 834 | } | ||
| 835 | else DISCARD (1); | ||
| 735 | NEXT; | 836 | NEXT; |
| 736 | 837 | ||
| 737 | CASE (Breturn): | 838 | CASE (Breturn): |
| @@ -791,11 +892,15 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, | |||
| 791 | if (sys_setjmp (c->jmp)) | 892 | if (sys_setjmp (c->jmp)) |
| 792 | { | 893 | { |
| 793 | struct handler *c = handlerlist; | 894 | struct handler *c = handlerlist; |
| 895 | int dest; | ||
| 794 | top = c->bytecode_top; | 896 | top = c->bytecode_top; |
| 795 | op = c->bytecode_dest; | 897 | dest = c->bytecode_dest; |
| 796 | handlerlist = c->next; | 898 | handlerlist = c->next; |
| 797 | PUSH (c->val); | 899 | PUSH (c->val); |
| 798 | goto op_branch; | 900 | CHECK_RANGE (dest); |
| 901 | /* Might have been re-set by longjmp! */ | ||
| 902 | stack.byte_string_start = SDATA (stack.byte_string); | ||
| 903 | stack.pc = stack.byte_string_start + dest; | ||
| 799 | } | 904 | } |
| 800 | 905 | ||
| 801 | NEXT; | 906 | NEXT; |
| @@ -1363,7 +1468,7 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, | |||
| 1363 | call3 (Qerror, | 1468 | call3 (Qerror, |
| 1364 | build_string ("Invalid byte opcode: op=%s, ptr=%d"), | 1469 | build_string ("Invalid byte opcode: op=%s, ptr=%d"), |
| 1365 | make_number (op), | 1470 | make_number (op), |
| 1366 | make_number (pc - 1 - bytestr_data)); | 1471 | make_number (stack.pc - 1 - stack.byte_string_start)); |
| 1367 | 1472 | ||
| 1368 | /* Handy byte-codes for lexical binding. */ | 1473 | /* Handy byte-codes for lexical binding. */ |
| 1369 | CASE (Bstack_ref1): | 1474 | CASE (Bstack_ref1): |
| @@ -1423,6 +1528,8 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, | |||
| 1423 | 1528 | ||
| 1424 | exit: | 1529 | exit: |
| 1425 | 1530 | ||
| 1531 | byte_stack_list = byte_stack_list->next; | ||
| 1532 | |||
| 1426 | /* Binds and unbinds are supposed to be compiled balanced. */ | 1533 | /* Binds and unbinds are supposed to be compiled balanced. */ |
| 1427 | if (SPECPDL_INDEX () != count) | 1534 | if (SPECPDL_INDEX () != count) |
| 1428 | { | 1535 | { |