From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!.POSTED.blaine.gmane.org!not-for-mail From: Andreas Politz Newsgroups: gmane.emacs.bugs Subject: bug#36609: 27.0.50; Possible race-condition in threading implementation Date: Thu, 11 Jul 2019 22:51:10 +0200 Message-ID: <87muhks3b5.fsf@hochschule-trier.de> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Injection-Info: blaine.gmane.org; posting-host="blaine.gmane.org:195.159.176.226"; logging-data="64648"; mail-complaints-to="usenet@blaine.gmane.org" User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/27.0.50 (gnu/linux) To: 36609@debbugs.gnu.org Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Thu Jul 11 22:52:17 2019 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane.org Original-Received: from lists.gnu.org ([209.51.188.17]) by blaine.gmane.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.89) (envelope-from ) id 1hlg37-000GYr-9S for geb-bug-gnu-emacs@m.gmane.org; Thu, 11 Jul 2019 22:52:17 +0200 Original-Received: from localhost ([::1]:45298 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hlg31-0005TB-6F for geb-bug-gnu-emacs@m.gmane.org; Thu, 11 Jul 2019 16:52:11 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:40428) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hlg2v-0005A9-32 for bug-gnu-emacs@gnu.org; Thu, 11 Jul 2019 16:52:07 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1hlg2s-000799-Do for bug-gnu-emacs@gnu.org; Thu, 11 Jul 2019 16:52:05 -0400 Original-Received: from debbugs.gnu.org ([209.51.188.43]:58290) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1hlg2s-000793-8R for bug-gnu-emacs@gnu.org; Thu, 11 Jul 2019 16:52:02 -0400 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1hlg2s-0007iO-5E for bug-gnu-emacs@gnu.org; Thu, 11 Jul 2019 16:52:02 -0400 X-Loop: help-debbugs@gnu.org Resent-From: Andreas Politz Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Thu, 11 Jul 2019 20:52:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: report 36609 X-GNU-PR-Package: emacs X-Debbugs-Original-To: bug-gnu-emacs@gnu.org Original-Received: via spool by submit@debbugs.gnu.org id=B.156287828929571 (code B ref -1); Thu, 11 Jul 2019 20:52:02 +0000 Original-Received: (at submit) by debbugs.gnu.org; 11 Jul 2019 20:51:29 +0000 Original-Received: from localhost ([127.0.0.1]:38869 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1hlg2J-0007gl-CP for submit@debbugs.gnu.org; Thu, 11 Jul 2019 16:51:28 -0400 Original-Received: from lists.gnu.org ([209.51.188.17]:59292) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1hlg2G-0007gU-UW for submit@debbugs.gnu.org; Thu, 11 Jul 2019 16:51:26 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:40206) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hlg2E-00053k-Am for bug-gnu-emacs@gnu.org; Thu, 11 Jul 2019 16:51:24 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1hlg2A-00065P-Ak for bug-gnu-emacs@gnu.org; Thu, 11 Jul 2019 16:51:21 -0400 Original-Received: from gateway-a.fh-trier.de ([143.93.54.181]:54341) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1hlg29-0005yw-CE for bug-gnu-emacs@gnu.org; Thu, 11 Jul 2019 16:51:18 -0400 X-Virus-Scanned: by Amavisd-new + Sophos + ClamAV [Rechenzentrum Hochschule Trier (RZ/HT)] Original-Received: from localhost (x4db620d5.dyn.telefonica.de [77.182.32.213]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) (Authenticated sender: politza) by gateway-a.fh-trier.de (Postfix) with ESMTPSA id 66AD81871025 for ; Thu, 11 Jul 2019 22:51:11 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha1; c=simple/simple; d=hochschule-trier.de; s=default; t=1562878271; bh=qnSNCUGUemvWSuEgtb8ZRHp0aC4=; h=From:To:Subject:Date:Message-ID:MIME-Version:Content-Type; b=WhZyrWX+pA5/+f8avRJmMYOeB8cHhcHVAjXk18QrzXRbj8ypbLEUZjITUr0ZVXlSN NGe4RssFYiry81j46DmN11GLQSTjZQh3tWLWSfxJkHBOxtbnhWleQm3FSE5xoKblt+ zgiPxlJeVkxXzKMuKTDHbs33HMdbpKbCprg5FIH8= X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6.x X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.51.188.43 X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Original-Sender: "bug-gnu-emacs" Xref: news.gmane.org gmane.emacs.bugs:162734 Archived-At: --=-=-= Content-Type: text/plain I think there is a race-condition in the implementation of threads. I tried to find a minimal test-case, without success. Thus, I've attached a lengthy source-file. Loading that file should trigger this bug and may freeze your session. Indications: 1. The main-thread has the name of one of created threads (XEmacs in this case), instead of "emacs". 2. Emacs stops processing all keyboard/mouse input while looping in wait_reading_process_output. Sending commands via emacsclient still works. GDB output: (gdb) info threads Id Target Id Frame * 1 Thread 0x7ffff17f5d40 (LWP 26264) "XEmacs" 0x000055555576eac0 in XPNTR (a=XIL(0x7ffff1312533)) at alloc.c:535 2 Thread 0x7ffff0ac4700 (LWP 26265) "gmain" 0x00007ffff50d1667 in poll () from /usr/lib/libc.so.6 3 Thread 0x7fffebd1a700 (LWP 26266) "gdbus" 0x00007ffff50d1667 in poll () from /usr/lib/libc.so.6 4 Thread 0x7fffeb519700 (LWP 26267) "dconf worker" 0x00007ffff50d1667 in poll () from /usr/lib/libc.so.6 (gdb) bt full #0 0x00007ffff50d3f76 in pselect () at /usr/lib/libc.so.6 #1 0x0000555555832e48 in really_call_select (arg=0x7fffffffd150) at thread.c:586 sa = 0x7fffffffd150 self = 0x555555c154e0 oldset = { __val = {0, 93825011232085, 140737488343064, 31632, 31632, 51840, 140737488343136, 93824994672716, 4294967298, 140737488343184, 93824999850720, 0, 0, 140737488343136, 93824993869565, 4041340661} } #2 0x0000555555774449 in flush_stack_call_func (func=0x555555832d81 , arg=0x7fffffffd150) at alloc.c:4969 end = 0x7fffffffd100 self = 0x555555c154e0 sentry = { o = { __max_align_ll = 140737488343296, __max_align_ld = } } #3 0x0000555555832f40 in thread_select (func=0x7ffff50d3eb0 , max_fds=6, rfds=0x7fffffffd260, wfds=0x7fffffffd2e0, efds=0x0, timeout=0x7fffffffd8b0, sigmask=0x0) at thread.c:616 sa = { func = 0x7ffff50d3eb0 , max_fds = 6, rfds = 0x7fffffffd260, wfds = 0x7fffffffd2e0, efds = 0x0, timeout = 0x7fffffffd8b0, sigmask = 0x0, result = 210347336 } #4 0x000055555585fea3 in xg_select (fds_lim=6, rfds=0x7fffffffd920, wfds=0x7fffffffd9a0, efds=0x0, timeout=0x7fffffffd8b0, sigmask=0x0) at xgselect.c:117 all_rfds = { fds_bits = {32, 0 } } all_wfds = { fds_bits = {0 } } tmo = { tv_sec = 7, tv_nsec = 140737488343264 } tmop = 0x7fffffffd8b0 context = 0x555555dae320 have_wfds = true gfds_buf = {{ fd = 0, events = 0, revents = 0 }, { fd = 32, events = 0, revents = 0 }, { fd = 0, events = 0, revents = 0 }, { fd = 7, events = 0, revents = 0 }, { fd = 8, events = 0, revents = 0 }, { fd = 15, events = 0, revents = 0 }, { fd = -11072, events = 32767, revents = 0 }, { fd = 1460278864, events = 21845, revents = 0 }, { fd = 64, events = 0, revents = 0 }, { fd = 0, events = 0, revents = 0 }, { fd = 2, events = 48, revents = 0 }, { fd = 0, events = 0, revents = 0 }, { fd = 91, events = 124, revents = 0 }, { fd = -397131776, events = 35414, revents = 11125 }, { fd = 1460278864, events = 21845, revents = 0 }, { fd = 1, events = 0, revents = 0 }, { fd = 2, events = 0, revents = 0 }, { fd = -11072, events = 32767, revents = 0 }, { fd = 1439161536, events = 21845, revents = 0 }, { fd = -11024, events = 32767, revents = 0 }, { fd = -11088, events = 32767, revents = 0 }, { fd = -182671191, events = 32767, revents = 0 }, { fd = 1, events = 0, revents = 0 }, { fd = -182670875, events = 32767, revents = 0 }, { fd = 194871296, events = 59160, revents = 48198 }, { fd = -1175563804, events = 19, revents = 0 }, { fd = 24, events = 0, revents = 0 }, { fd = 1460278864, events = 21845, revents = 0 }, { fd = 2, events = 0, revents = 0 }, { fd = 1439882448, events = 21845, revents = 0 }, { fd = 2, events = 0, revents = 0 }, { fd = 2, events = 0, revents = 0 }, { fd = 1, events = 2, revents = 0 }, { fd = 1460278864, events = 21845, revents = 0 }, { fd = 0, events = 0, revents = 0 }, { fd = -397131776, events = 35414, revents = 11125 }, { fd = 24, events = 0, revents = 0 }, { fd = 1439161536, events = 21845, revents = 0 }, { fd = 2, events = 0, revents = 0 }, { fd = 1, events = 0, revents = 0 }, { fd = 1439161536, events = 21845, revents = 0 }, { fd = -182606722, events = 32767, revents = 0 }, { fd = -10960, events = 32767, revents = 0 }, { fd = 1433487750, events = 21845, revents = 0 }, { fd = -10976, events = 32767, revents = 0 }, { fd = 1439161536, events = 21845, revents = 0 }, { fd = -30, events = 0, revents = 0 }, { fd = 1, events = 0, revents = 0 }, { fd = 1, events = 64, revents = 0 }, { fd = 1562877925, events = 0, revents = 0 }, { fd = 31, events = 0, revents = 0 }, { fd = 1562877925, events = 0, revents = 0 }, { fd = -10960, events = 32767, revents = 0 }, { fd = 1434542700, events = 21845, revents = 0 }, { fd = -10912, events = 32767, revents = 0 }, { fd = 1439161536, events = 21845, revents = 0 }, { fd = 1562877925, events = 0, revents = 0 }, { fd = -397131776, events = 35414, revents = 11125 }, { fd = -10848, events = 32767, revents = 0 }, { fd = 1434543288, events = 21845, revents = 0 }, { fd = 1460274293, events = 21845, revents = 0 }, { fd = 1385447426, events = 931, revents = 0 }, { fd = 95390, events = 0, revents = 0 }, { fd = 1433865373, events = 7256, revents = 10134 }, { fd = 1562877925, events = 0, revents = 0 }, { fd = 1439161536, events = 21845, revents = 0 }, { fd = 664149, events = 0, revents = 0 }, { fd = 80000, events = 0, revents = 0 }, { fd = 1562877925, events = 0, revents = 0 }, { fd = 664149080, events = 0, revents = 0 }, { fd = 1562877925, events = 0, revents = 0 }, { fd = 664149080, events = 0, revents = 0 }, { fd = -10752, events = 32767, revents = 0 }, { fd = 1434543494, events = 21845, revents = 0 }, { fd = 0, events = 0, revents = 0 }, { fd = -10544, events = 32767, revents = 0 }, { fd = 499622378, events = 0, revents = 0 }, { fd = 0, events = 0, revents = 0 }, { fd = 0, events = 0, revents = 0 }, { fd = 499622378, events = 0, revents = 0 }, { fd = -10688, events = 32767, revents = 0 }, { fd = 1434939197, events = 21845, revents = 0 }, { fd = 1562877925, events = 0, revents = 0 }, { fd = 164526702, events = 0, revents = 0 }, { fd = 1562877925, events = 0, revents = 0 }, { fd = 664149080, events = 0, revents = 0 }, { fd = -10544, events = 32767, revents = 0 }, { fd = 499622378, events = 41450, revents = 7623 }, { fd = 0, events = 0, revents = 0 }, { fd = 1562877925, events = 0, revents = 0 }, { fd = 0, events = 0, revents = 0 }, { fd = -1, events = 65535, revents = 65535 }, { fd = -10432, events = 32767, revents = 0 }, { fd = 1433359581, events = 21845, revents = 0 }, { fd = 0, events = 0, revents = 0 }, { fd = 0, events = 0, revents = 0 }, { fd = 0, events = 0, revents = 0 }, { fd = 1443725184, events = 85, revents = 0 }, { fd = 1450650965, events = 21845, revents = 0 }, { fd = 1450650965, events = 21845, revents = 0 }, { fd = 0, events = 0, revents = 0 }, { fd = 16384, events = 0, revents = 0 }, { fd = 5, events = 0, revents = 0 }, { fd = -10496, events = 32767, revents = 0 }, { fd = 0, events = 0, revents = 0 }, { fd = -1, events = 65535, revents = 65535 }, { fd = 1562877925, events = 0, revents = 0 }, { fd = 164526702, events = 0, revents = 0 }, { fd = 719, events = 0, revents = 0 }, { fd = 893997157, events = 0, revents = 0 }, { fd = 1439269600, events = 21845, revents = 0 }, { fd = 0, events = 0, revents = 0 }, { fd = 0, events = 0, revents = 0 }, { fd = -10496, events = 32767, revents = 0 }, { fd = 1433288445, events = 21845, revents = 0 }, { fd = 0, events = 0, revents = 0 }, { fd = 164532384, events = 0, revents = 0 }, { fd = 1562977925, events = 0, revents = 0 }, { fd = 1562977925, events = 0, revents = 0 }, { fd = 164532384, events = 0, revents = 0 }, { fd = -10368, events = 32767, revents = 0 }, { fd = 1434938909, events = 21845, revents = 0 }, { fd = 100000, events = 0, revents = 0 }, { fd = 0, events = 0, revents = 0 }, { fd = 1562877925, events = 0, revents = 0 }, { fd = 164532384, events = 0, revents = 0 }, { fd = -1, events = 65535, revents = 65535 }, { fd = 0, events = 0, revents = 0 }} gfds = 0x7fffffffd360 gfds_size = 128 n_gfds = -1 retval = 0 our_fds = 0 max_fds = 5 context_acquired = false i = 0 nfds = 135 tmo_in_millisec = 1030 must_free = 0 need_to_dispatch = false #5 0x0000555555802a78 in wait_reading_process_output (time_limit=0, nsecs=0, read_kbd=-1, do_display=true, wait_for_cell=XIL(0), wait_proc=0x0, just_wait_proc=0) at process.c:5423 process_skipped = false channel = 6 nfds = 1 Available = { fds_bits = {32, 0 } } Writeok = { fds_bits = {0 } } check_write = true check_delay = 0 no_avail = false xerrno = 11 proc = XIL(0x7fffffffd9a0) timeout = { tv_sec = 0, tv_nsec = 499622378 } end_time = { tv_sec = 93824993869565, tv_nsec = 0 } timer_delay = { tv_sec = 0, tv_nsec = 499622378 } got_output_end_time = { tv_sec = 1562977205, tv_nsec = 270561059 } wait = FOREVER got_some_output = -1 prev_wait_proc_nbytes_read = 0 retry_for_async = false count = 4 now = { tv_sec = 0, tv_nsec = -1 } #6 0x00005555556f4718 in kbd_buffer_get_event (kbp=0x7fffffffdc70, used_mouse_menu=0x7fffffffe235, end_time=0x0) at keyboard.c:3836 do_display = true obj = make_fixnum(1073741816) #7 0x00005555556f06c5 in read_event_from_main_queue (end_time=0x0, local_getcjmp=0x7fffffffe040, used_mouse_menu=0x7fffffffe235) at keyboard.c:2138 c = XIL(0) save_jump = {{ __jmpbuf = {0, 0, 0, 0, 0, 0, 0, 0}, __mask_was_saved = 0, __saved_mask = { __val = {0 } } }} kb = 0x7fffffffdcd0 count = 3 #8 0x00005555556f099b in read_decoded_event_from_main_queue (end_time=0x0, local_getcjmp=0x7fffffffe040, prev_event=XIL(0), used_mouse_menu=0x7fffffffe235) at keyboard.c:2202 nextevt = XIL(0) frame = 0x1dcd30d9 terminal = 0x9 events = {XIL(0), XIL(0x1dcd30d9), XIL(0xca80), XIL(0x2b758a56e8544000), XIL(0), XIL(0x555556772ff5), XIL(0x7fffffffde50), XIL(0x5555556f57d8), XIL(0x555555c982e0), XIL(0), XIL(0), XIL(0x7fffffffde50), XIL(0x5555556e3efd), XIL(0x1dcd30d9), XIL(0x7fffffffde90), XIL(0x5555556f3b29)} n = 0 #9 0x00005555556f2236 in read_char (commandflag=1, map=XIL(0x5555567756e3), prev_event=XIL(0), used_mouse_menu=0x7fffffffe235, end_time=0x0) at keyboard.c:2810 c = XIL(0) jmpcount = 3 local_getcjmp = {{ __jmpbuf = {0, -245616553674816983, 93825011232757, 51840, 0, 0, -245616553305718231, -6214351577293929943}, __mask_was_saved = 0, __saved_mask = { __val = {0, 0, 140737488347312, 93824993869565, 0, 140737488347424, 93824994673374, 93825011242707, 3, 0, 0, 140737488347424, 93824994446493, 93824999850720, 0, 0} } }} save_jump = {{ __jmpbuf = {93824993869565, 0, 140737488347584, 93824994020698, 0, 51840, -1, 0}, __mask_was_saved = 1450661587, __saved_mask = { __val = {93825011242723, 140737488347520, 93824993870282, 93825011242707, 93825011242723, 140737488347584, 93824994446493, 93824999885184, 34464, 34464, 140737488347584, 93824993869565, 40105367251, 93825004306304, 140737488347624, 93824999850720} } }} tem = XIL(0x2aaa9b29c970) save = XIL(0) previous_echo_area_message = XIL(0) also_record = XIL(0) reread = false recorded = false polling_stopped_here = true orig_kboard = 0x555555dfa570 #10 0x00005555556ff6c8 in read_key_sequence (keybuf=0x7fffffffe440, prompt=XIL(0), dont_downcase_last=false, can_return_switch_frame=true, fix_current_buffer=true, prevent_redisplay=false) at keyboard.c:9124 interrupted_kboard = 0x555555dfa570 interrupted_frame = 0x5555560d7f80 key = XIL(0x5555557a7eff) used_mouse_menu = false echo_local_start = 0 last_real_key_start = 0 keys_local_start = 0 new_binding = XIL(0x7fffffffe310) count = 3 t = 0 echo_start = 0 keys_start = 0 current_binding = XIL(0x5555567756e3) first_unbound = 31 mock_input = 0 used_mouse_menu_history = {false } fkey = { parent = XIL(0x555555d6ce03), map = XIL(0x555555d6ce03), start = 0, end = 0 } keytran = { parent = XIL(0x7ffff14a7dbb), map = XIL(0x7ffff14a7dbb), start = 0, end = 0 } indec = { parent = XIL(0x555555d6cdf3), map = XIL(0x555555d6cdf3), start = 0, end = 0 } shift_translated = false delayed_switch_frame = XIL(0) original_uppercase = XIL(0) original_uppercase_position = -1 dummyflag = false starting_buffer = 0x7ffff0e1f6f0 fake_prefixed_keys = XIL(0) first_event = XIL(0) second_event = XIL(0) #11 0x00005555556ee5fb in command_loop_1 () at keyboard.c:1348 cmd = XIL(0) keybuf = {XIL(0x7fffffffe490), XIL(0x5555557a804c), make_fixnum(11545945833472), XIL(0x7fffffffe4c0), XIL(0x555555c982e0), XIL(0), XIL(0), XIL(0x7fffffffe490), XIL(0x5555556e3efd), XIL(0xf0e1f6f5), XIL(0x7fffffffe500), make_fixnum(23456248668343), XIL(0x555555d18953), XIL(0x3), XIL(0x555555c982e0), XIL(0), XIL(0), XIL(0x7fffffffe4e0), XIL(0x5555556e3efd), XIL(0xf0e1f6f5), XIL(0x7fffffffe520), XIL(0x5555557a2e69), XIL(0x1556e3efd), XIL(0x5760), XIL(0x7fffffffe540), XIL(0x555555d53470), XIL(0), XIL(0), XIL(0x7fffffffe550), make_fixnum(23456248662876)} i = 32767 prev_modiff = 0 prev_buffer = 0x0 already_adjusted = false #12 0x00005555557a2a64 in internal_condition_case (bfun=0x5555556ee1b3 , handlers=XIL(0x5760), hfun=0x5555556ed968 ) at eval.c:1351 val = XIL(0x5555556e3efd) c = 0x555555d53470 #13 0x00005555556ede9b in command_loop_2 (ignore=XIL(0)) at keyboard.c:1091 val = XIL(0) #14 0x00005555557a22d5 in internal_catch (tag=XIL(0xd110), func=0x5555556ede6e , arg=XIL(0)) at eval.c:1112 val = XIL(0x45b00000000) c = 0x555555d53340 #15 0x00005555556ede39 in command_loop () at keyboard.c:1070 #16 0x00005555556ed537 in recursive_edit_1 () at keyboard.c:714 count = 1 val = make_fixnum(23456248667937) #17 0x00005555556ed6bb in Frecursive_edit () at keyboard.c:786 count = 0 buffer = XIL(0) #18 0x00005555556eb49d in main (argc=4, argv=0x7fffffffe8b8) at emacs.c:2086 stack_bottom_variable = 0x20 do_initial_setlocale = true no_loadup = false junk = 0x0 dname_arg = 0x0 ch_to_dir = 0x0 original_pwd = 0x0 dump_mode = 0x0 skip_args = 0 temacs = 0x0 attempt_load_pdump = true rlim = { rlim_cur = 10022912, rlim_max = 18446744073709551615 } sockfd = -1 --=-=-= Content-Type: text/plain Content-Disposition: attachment; filename=thread-bug-2.el Content-Description: thread-bug-2.el ;; -*- lexical-binding: t -*- (require 'threads) (require 'eieio) (require 'cl-lib) (require 'ring) (defun debug (fmt &rest args) (princ (apply #'format fmt args) #'external-debugging-output) (terpri #'external-debugging-output)) (define-error 'thread-utils-thread-interrupted "Thread was interrupted" 'error) (defun thread-utils-main-thread-p (&optional object) (let ((object (or object (current-thread)))) (and (threadp object) (eq object (car (all-threads)))))) (defun thread-utils-quitable-apply (fn &rest args) (let* ((this-thread (current-thread)) (quit-thread (make-thread (lambda nil (condition-case nil (cl-loop (sleep-for 3)) (quit (thread-signal this-thread 'quit nil)) (thread-utils-thread-interrupted nil)))))) (unwind-protect (apply fn args) (thread-signal quit-thread 'thread-utils-thread-interrupted nil)))) (defun thread-utils-condition-quitable-wait (condition) (cl-check-type condition condition-variable) (thread-utils-quitable-apply #'condition-wait condition)) (defun thread-utils-condition-wait (condition) (if (thread-utils-main-thread-p) (thread-utils-condition-quitable-wait condition) (condition-wait condition))) (defconst channel-default-capacity 16) (defclass channel-terminal nil ((mutex :initarg :mutex :type mutex) (condition :initarg :condition :type condition-variable) (msg-queue :initarg :msg-queue :type ring) (closed-p :initform nil) (other-terminal :type (or null channel-terminal)))) (defclass channel-source (channel-terminal) nil) (defclass channel-sink (channel-terminal) nil) (define-error 'channel-closed "Trying to send/recv from a closed channel") (defun make-channel (&optional capacity) (unless capacity (setq capacity channel-default-capacity)) (cl-check-type capacity (integer 1 *)) (let* ((mutex (make-mutex "channel")) (condition (make-condition-variable mutex "channel")) (msg-queue (make-ring capacity)) (source (channel-source :mutex mutex :condition condition :msg-queue msg-queue)) (sink (channel-sink :mutex mutex :condition condition :msg-queue msg-queue))) (oset source other-terminal sink) (oset sink other-terminal source) (cons source sink))) (cl-defgeneric channel-send ((source channel-source) message) (with-mutex (oref source mutex) (with-slots (condition msg-queue) source (while (and (not (channel-closed-p source)) (= (ring-size msg-queue) (ring-length msg-queue))) (thread-utils-condition-wait condition)) (when (channel-closed-p source) (signal 'channel-closed (list source))) (let ((inhibit-quit t)) (ring-insert msg-queue message) (when (= 1 (ring-length msg-queue)) (condition-notify condition t))) nil))) (cl-defgeneric channel-recv ((sink channel-terminal)) (with-mutex (oref sink mutex) (with-slots (condition msg-queue) sink (while (and (not (channel-closed-p sink)) (ring-empty-p msg-queue)) (thread-utils-condition-wait condition)) (when (channel-closed-p sink) (signal 'channel-closed (list sink))) (let ((inhibit-quit t)) (prog1 (ring-remove msg-queue) (when (= 1 (- (ring-size msg-queue) (ring-length msg-queue))) (condition-notify condition t))))))) (cl-defgeneric channel-peek ((sink channel-terminal)) (with-mutex (oref sink mutex) (with-slots (condition msg-queue) sink (while (and (not (channel-closed-p sink)) (ring-empty-p msg-queue)) (thread-utils-condition-wait condition)) (when (channel-closed-p sink) (signal 'channel-closed (list sink))) (ring-ref msg-queue -1)))) (cl-defgeneric channel-close ((terminal channel-terminal)) (with-mutex (oref terminal mutex) (with-slots (closed-p condition) terminal (setq closed-p t) (condition-notify condition t)) nil)) (cl-defmethod channel-closed-p ((source channel-source)) (with-mutex (oref source mutex) (with-slots (closed-p other-terminal) source (or closed-p (oref other-terminal closed-p))))) (cl-defmethod channel-closed-p ((sink channel-sink)) (with-mutex (oref sink mutex) (with-slots (closed-p other-terminal msg-queue) sink (or closed-p (and (oref other-terminal closed-p) (ring-empty-p msg-queue)))))) (defclass future nil ((channel :initform (make-channel 1)))) (defun make-future () (make-instance 'future)) (cl-defgeneric future-set ((future future) value) (with-slots (channel) future (let ((inhibit-quit t)) (condition-case nil (progn (debug "Sending future") (channel-send (car channel) value) (debug "Future send")) (channel-closed (signal 'error (list future)))) (debug "Closing future") (channel-close (car channel)) (debug "Future closed")))) (cl-defgeneric future-get ((future future)) (with-slots (channel) future (debug "Getting future") (channel-peek (cdr channel)) (debug "Future got"))) (defclass future-deferred (future) ((producer :initarg :producer :type function) (value-produced-p :initform nil) (mutex :initform (make-mutex "future-deferred")))) (defun make-deferred-future (producer) (make-instance 'future-deferred :producer producer)) (cl-defmethod future-get :before ((future future-deferred)) (with-slots (mutex value-produced-p producer) future (with-mutex mutex (unless value-produced-p (unwind-protect (make-thread (lambda nil (debug "Setting Future") (future-set future (funcall producer)) (debug "Future set")) "XEmacs") (setq value-produced-p t)))))) (let ((future (make-deferred-future (lambda nil 42)))) (future-get future)) --=-=-=--