> From: "Micah Brodsky" <micah...@csail.mit.edu> > Date: Thu, 26 Apr 2012 22:36:21 -0400 > > [...] entirely irrelevant to MIT Scheme, except inasmuch as the same > problems reappear and are much more of a pain to deal with without > them. I.e., as far as I can tell, everyone who wants to abort a > blocking call like a socket read has to roll their own abstraction > to handle safe cross-thread signaling.
Hey, we are already in the weeds. Let's not joke about rolling our own... :-) ... and let's get concrete with the existing thread-event mechanism. To throw an error/abort in a thread blocked in channel-read (e.g. read-line), you should be able to do this: (signal-thread-event thread (lambda () (error "Abort!"))) Thread would be the blocked reader, perhaps (thread-mutex-owner (port/thread-mutex socket)) Here's our example again, spiffed up with some messages, minus the curious nested create-thread. (let ((socket (open-tcp-server-socket 54321))) (create-thread #f (lambda () (let ((port (tcp-server-connection-accept socket #t #f))) (display ";Connection accepted.\n") (for-each display (list ";Read: " (ignore-errors (lambda () (read-line port))) "\n")) (display "ok\n" port) (close-port port) (display ";Connection disconnected.\n"))))) Entering that into the console REPL, I get the REPL prompt back and I can connect via `nc localhost 54321'. When I connect ";Connection accepted." appears on my console: ;Value 11: #[thread 11] 1 ]=> ;Connection accepted. I then enter at the REPL the charm already mentioned: (signal-thread-event #@11 (lambda () (error "Abort!"))) and I see this: ;Unspecified return value 1 ]=> ;Read: #[condition 12 simple-error] ;Connection disconnected. (pp #@11) #[thread 11] (execution-state dead) ... My nc command emits "ok" and exits without error. If I had kept #[thread 11] out of the REPL's hash table, it would be garbage collected too. When I punt the ignore-errors wrapper I see this: ;Unspecified return value 1 ]=> ;The thread #[thread 11] signalled an error: Abort! ;To continue, call RESTART with an option number: ; (RESTART 1) => Return to read-eval-print level 1. 2 error> The situation is quite sane. Here is the output of the debugger's history command: SL# Procedure-name Expression 0 (begin (event) (set-interrupt-enables! int ... 1 (begin (if event (let ((block? (%record-re ... 2 (let ((any-events? (handle-thread-events t ... 3 (begin (%suspend-current-thread) result) 4 (let ((value (let ((result (quote interrup ... 5 (let ((result (TEST-FOR-IO-ON-CHANNEL chan ... 6 (let ((value (thunk))) (set-interrupt-enab ... 7 (let ((n (do-read 0))) (if n (begin (%reco ... 8 fill-input-buffer (let ((n (read-bytes ib))) (if n (if (grea ... 9 (let ((r (fill-input-buffer ib))) (let ((t ... 10 (let ((char (defer port))) (transcribe-inp ... 11 loop (let ((char (read-char port))) (cond ((eq? ... 12 (list ";Read: " (read-line port) "\n") 13 (for-each display (list ";Read: " (read-li ... 14 (begin (for-each display (list ";Read: " ( ... 15 (exit-current-thread (thunk)) 16 loop (loop (bind-abort-restart cmdl (lambda () ... 3 debug> Actually I upcased test-for-io-on-channel because I think it is cool that I can see where my #[thread 11] was hanging out when it got the bad news. That's Bodacious, dude. > [...] Imagine if you couldn't safely do debug prints from a worker thread! I can only imagine doing it safely if the debug-print procedure grabs the port/mutex for the duration of the message output (write-line?) process. A write-line made up of tiny atomic write-chars is no more "safe" except for the precious buffer pointers. I would call them a costly set of suspenders IF they kept the pants from falling down. Thread-safe and child-proof are marketing terms. > I have not looked at the spec or code in the case of glibc, but I > know for certain MS's stdio and iostream protect their buffers with > locks. Marketing term. Definitely. Tiny atomic ops won't keep your pants up! > MIT Scheme has some particularly bad failure modes when you rub its > sockets the wrong way from multiple threads, i.e. producing an > infinite explosion of interrupt-triggered errors that surfaces on > socket close, well after the offending code has run, and almost > un-debuggable because all you can interact through is the interrupt > menu. The only way I figured that one out is by asking Taylor to > tell me what I did wrong. :P Fascinating (as my hero would say, without a trace of sarcasm). What did you do wrong? _______________________________________________ MIT-Scheme-devel mailing list MIT-Scheme-devel@gnu.org https://lists.gnu.org/mailman/listinfo/mit-scheme-devel