From: David L. R. <ra...@cs...> - 2009-12-20 00:06:01
|
Greetings SBCL Devel, This is a continuation of another thread, which can be found at: http://sourceforge.net/mailarchive/forum.php?thread_name=633...@ma...&forum_name=sbcl-help I've created a patch for both lutex and futex implementations of condition-wait that supports waiting on a condition variable with a timeout. I include said patch below the resources I examined. Does this patch look on the way to something that could be distributed with SBCL? My main question concerns interrupts. The futex code checks for interrupts every 10 ms. Should I modify the lutex code to do the same? I did not include the checking for now, based on the idea that if such checks were necessary, it would have been in the lutex code in the first place. Another question concerns the return value of condition-wait when there was a timeout. As of now, the lutex code returns 1. This is slightly inconsistent with the current lutex behavior, where condition-wait always returns 0, if it returns a value at all. Do we care? It seems reasonable that the return value should be an unreliable indicator for whether a condition variable was signaled (for a reliable indicator, an object similar to CCL's semaphore-notification-object [search for "ccl make-semaphore-notification"] would be required). It looks to me like waiting without a timeout on futexes and lutexes return different values anyway. Thanks, David Some resources I looked into while creating this patch include: (1) sa2c's explanation as to why the lutex implementation is better than the futex implementation http://article.gmane.org/gmane.lisp.steel-bank.devel/8041 (2) An IRC log with some random relevant information. Search for "sa2c" to get to the relevant stuff. http://tunes.org/~nef//logs/lisp/07.05.02 (3) Part of the "Futexes are Tricky" writeup. http://people.redhat.com/drepper/futex.pdf (4) Some notes on pthread_cond_[timed]wait http://www.opengroup.org/onlinepubs/000095399/functions/pthread_cond_timedwait.html ========== Begin patch formed from a git diff master ========== diff --git a/src/code/target-thread.lisp b/src/code/target-thread.lisp index ad83197..f843166 100644 --- a/src/code/target-thread.lisp +++ b/src/code/target-thread.lisp @@ -213,7 +213,8 @@ created and old ones may exit at any time." int (lutex unsigned-long)) (define-alien-routine ("lutex_wait" %lutex-wait) - int (queue-lutex unsigned-long) (mutex-lutex unsigned-long)) + int (queue-lutex unsigned-long) (mutex-lutex unsigned-long) + (n long) (m unsigned-long)) (define-alien-routine ("lutex_wake" %lutex-wake) int (lutex unsigned-long) (n int)) @@ -520,17 +521,19 @@ IF-NOT-OWNER is :FORCE)." :structure waitqueue :slot data) -(defun condition-wait (queue mutex) +(defun condition-wait (queue mutex &key timeout) #!+sb-doc "Atomically release MUTEX and enqueue ourselves on QUEUE. Another thread may subsequently notify us using CONDITION-NOTIFY, at which -time we reacquire MUTEX and return to the caller." +time we reacquire MUTEX and return to the caller. TIMEOUT is specified +in seconds." #!-sb-thread (declare (ignore queue)) (assert mutex) #!-sb-thread (error "Not supported in unithread builds.") #!+sb-thread (let ((me *current-thread*)) (assert (eq me (mutex-%owner mutex))) + (assert (or (null timeout) (typep timeout 'integer))) (/show0 "CONDITION-WAITing") #!+sb-lutex ;; Need to disable interrupts so that we don't miss setting the @@ -540,10 +543,16 @@ time we reacquire MUTEX and return to the caller." (unwind-protect (progn (setf (mutex-%owner mutex) nil) - (with-lutex-address (queue-lutex-address (waitqueue-lutex queue)) - (with-lutex-address (mutex-lutex-address (mutex-lutex mutex)) - (with-local-interrupts - (%lutex-wait queue-lutex-address mutex-lutex-address))))) + (multiple-value-bind (to-sec to-usec) (decode-timeout timeout) + (with-lutex-address (queue-lutex-address (waitqueue-lutex queue)) + (with-lutex-address (mutex-lutex-address (mutex-lutex mutex)) + (with-local-interrupts + (%lutex-wait queue-lutex-address + mutex-lutex-address + ;; our way if saying "no + ;; timeout": + (or to-sec -1) + (or to-usec 0))))))) (setf (mutex-%owner mutex) me))) #!-sb-lutex ;; Need to disable interrupts so that we don't miss grabbing the @@ -556,7 +565,7 @@ time we reacquire MUTEX and return to the caller." ;; continuing after a deadline or EINTR. (setf (waitqueue-data queue) me) (loop - (multiple-value-bind (to-sec to-usec) (decode-timeout nil) + (multiple-value-bind (to-sec to-usec) (decode-timeout timeout) (case (unwind-protect (with-pinned-objects (queue me) ;; RELEASE-MUTEX is purposefully as close to @@ -585,7 +594,7 @@ time we reacquire MUTEX and return to the caller." ;; better than nothing. (allow-with-interrupts (get-mutex mutex))) ;; ETIMEDOUT - ((1) (signal-deadline)) + ((1) (if timeout (return) (signal-deadline))) ;; EINTR ((2)) ;; EWOULDBLOCK, -1 here, is the possible spurious wakeup diff --git a/src/runtime/GNUmakefile b/src/runtime/GNUmakefile index cfaac20..70d9d68 100644 --- a/src/runtime/GNUmakefile +++ b/src/runtime/GNUmakefile @@ -23,7 +23,7 @@ NM = nm -gp DEPEND_FLAGS = -MM GREP = grep -CFLAGS = -g -Wall -Wsign-compare -O3 +CFLAGS = -g -Wall -Wsign-compare -O3 -D_GNU_SOURCE ASFLAGS = $(CFLAGS) CPPFLAGS = -I. diff --git a/src/runtime/pthread-lutex.c b/src/runtime/pthread-lutex.c index 6365214..57a03bf 100644 --- a/src/runtime/pthread-lutex.c +++ b/src/runtime/pthread-lutex.c @@ -93,14 +93,35 @@ lutex_init (tagged_lutex_t tagged_lutex) } int -lutex_wait (tagged_lutex_t tagged_queue_lutex, tagged_lutex_t tagged_mutex_lutex) +lutex_wait (tagged_lutex_t tagged_queue_lutex, tagged_lutex_t tagged_mutex_lutex, + long sec, unsigned long usec) { int ret; struct lutex *queue_lutex = (struct lutex*) native_pointer(tagged_queue_lutex); struct lutex *mutex_lutex = (struct lutex*) native_pointer(tagged_mutex_lutex); + struct timeval tv; + struct timespec timeout; + + /* computation of timeout taken from pthread-futex.c */ + if (sec >= 0) { + ret = gettimeofday(&tv, NULL); + if (ret != 0) + return ret; + timeout.tv_sec = tv.tv_sec + sec + (tv.tv_usec + usec) / 1000000; + timeout.tv_nsec = (tv.tv_usec + usec) % 1000000; + } - ret = pthread_cond_wait(queue_lutex->condition_variable, mutex_lutex->mutex); - lutex_assert(ret == 0); + if (sec >= 0) { + ret = pthread_cond_timedwait(queue_lutex->condition_variable, + mutex_lutex->mutex, &timeout); + } else { + ret = pthread_cond_wait(queue_lutex->condition_variable, + mutex_lutex->mutex); + } + + lutex_assert(ret == 0 || ret == ETIMEDOUT); + if (ret == ETIMEDOUT) + return 1; return ret; } |
From: Nikodemus S. <nik...@ra...> - 2009-12-20 08:15:43
|
2009/12/20 David L. Rager <ra...@cs...>: > My main question concerns interrupts. The futex code checks for > interrupts every 10 ms. Should I modify the lutex code to do the > same? I did not include the checking for now, based on the idea that > if such checks were necessary, it would have been in the lutex code in > the first place. No, what you did is fine. The futex code you looked at was probably the pthread-futex stuff, which emulates the Linux futex API on top of pthreads for lesser operating systems. The real futex code that gets used on Linux lives in src/runtime/linux-os.c. As long as we can, let the OS deal with the timeouts, since it can hopefully do a better job. > Another question concerns the return value of condition-wait when > there was a timeout. As of now, the lutex code returns 1. This is > slightly inconsistent with the current lutex behavior, where > condition-wait always returns 0, if it returns a value at all. Do we > care? It seems reasonable that the return value should be an > unreliable indicator for whether a condition variable was signaled > (for a reliable indicator, an object similar to CCL's > semaphore-notification-object [search for "ccl > make-semaphore-notification"] would be required). It looks to me like > waiting without a timeout on futexes and lutexes return different > values anyway. I think as long as we are living with deadlines in addition to local timeouts, the only right thing is to call (SIGNAL-DEADLINE) on timeout, because you easily cannot tell if the timeout was due to the local timeout or the global deadline. So code that _expects_ timeouts will look something like (handler-case (condition-wait ... :timeout 0.1) (timeout () (whatever-we-want-to-do-in-case-of-timeout)) while I think explicit return-values are in most cases much nicer for timeouts, using serious-conditions to indicate them is more foolproof in some ways. (Almost all of our synchronization primitives could do with some API refactoring, but I don't think that's a prequisite for this patch. It should also be noted that what Paul Khuong has cooking might supersede lutexes sooner or later, but I'd rather take that risk than let this fall on the floor...) Some comments on the patch: > + (assert (or (null timeout) (typep timeout 'integer))) It would be better to allow reals instead of integers. You should be able to just call DECODE-TIMEOUT using the TIMEOUT argument -- though it might be better to DECLAIM the FTYPE of CONDITION-WAIT approriately as well. > - ((1) (signal-deadline)) > + ((1) (if timeout (return) (signal-deadline))) As discussed above. Similar code needed for the SB-LUTEX case as well. > -CFLAGS = -g -Wall -Wsign-compare -O3 > +CFLAGS = -g -Wall -Wsign-compare -O3 -D_GNU_SOURCE Since AFAIK this is only necessary for being able to build the lutex code on Linux, I think this is probably better left out of the final patch. (...but as John Fremlin noted just yesterday, we should really be inhering CFLAGS from environment, or at least provide a way to explicitly pass them to the build for things like defining non-standard SBCL_HOME. > + /* computation of timeout taken from pthread-futex.c */ > + if (sec >= 0) { > + ret = gettimeofday(&tv, NULL); > + if (ret != 0) > + return ret; > + timeout.tv_sec = tv.tv_sec + sec + (tv.tv_usec + usec) / 1000000; > + timeout.tv_nsec = (tv.tv_usec + usec) % 1000000; > + } In and ideal world we might abstract this out, but as OAOO violations and SBCL go this is pretty small. :) All in all, this is looking pretty good. The biggest thing missing are test-cases. :) Some of the test-cases in tests/deadline.impure.lisp should be enabled for SB-LUTEX when this code and the timeout signalling is in place. (No, I didn't actually run any of this yet.) Cheers, -- Nikodemus |
From: David L. R. <ra...@cs...> - 2009-12-20 23:34:51
|
Hi Nikodemus, First, thanks for your thoughtful and timely responses to my inquiries. I'm treating this email like a code review @ a large SWE company and inlining my responses. One new thing I should mention: the time out of the lutexes varies a lot. E.g, if I request a one second timeout, the lutex will timeout after 0.91 seconds. If I request a 60 second timeout, it timesout after 59.5 seconds. This strikes me as odd, but since an approximation is good enough for my use case, I'm tempted to ignore this issue for now. >> My main question concerns interrupts. The futex code checks for >> interrupts every 10 ms. Should I modify the lutex code to do the >> same? I did not include the checking for now, based on the idea that >> if such checks were necessary, it would have been in the lutex code in >> the first place. > > No, what you did is fine. The futex code you looked at was probably > the pthread-futex stuff, which emulates the Linux futex API on top of > pthreads for lesser operating systems. The real futex code that gets > used on Linux lives in src/runtime/linux-os.c. > > As long as we can, let the OS deal with the timeouts, since it can > hopefully do a better job. Okay. >> Another question concerns the return value of condition-wait when >> there was a timeout. As of now, the lutex code returns 1. This is >> slightly inconsistent with the current lutex behavior, where >> condition-wait always returns 0, if it returns a value at all. Do we >> care? It seems reasonable that the return value should be an >> unreliable indicator for whether a condition variable was signaled >> (for a reliable indicator, an object similar to CCL's >> semaphore-notification-object [search for "ccl >> make-semaphore-notification"] would be required). It looks to me like >> waiting without a timeout on futexes and lutexes return different >> values anyway. > > I think as long as we are living with deadlines in addition to local > timeouts, the only right thing is to call (SIGNAL-DEADLINE) on > timeout, because you easily cannot tell if the timeout was due to the > local timeout or the global deadline. > > So code that _expects_ timeouts will look something like > > (handler-case (condition-wait ... :timeout 0.1) > (timeout () (whatever-we-want-to-do-in-case-of-timeout)) I'm a bit confused as to what you mean by "local timeout" versus "global deadline?" Does "global deadline" refer to functions similar to the sb-impl:with-deadline that I see in tests/deadline.impure.lisp? My personal preference is to avoid this handler-case and instead (1) use the return value as an estimate of whether the signal was received and (2) a notification-object to know for certain. This notification-object should probably be added in a different patch. For all of my use cases, it doesn't matter whether the signal wasn't received due to timeout or for some other reason (like the thread being killed). If the signal was received, I do one thing; otherwise I do another. Anyway, I think your answer to my question in the previous paragraph will help address this concern. > while I think explicit return-values are in most cases much nicer for > timeouts, using serious-conditions to indicate them is more foolproof > in some ways. > > (Almost all of our synchronization primitives could do with some API > refactoring, but I don't think that's a prequisite for this patch. It > should also be noted that what Paul Khuong has cooking might supersede > lutexes sooner or later, but I'd rather take that risk than let this > fall on the floor...) > > Some comments on the patch: > >> + (assert (or (null timeout) (typep timeout 'integer))) > > It would be better to allow reals instead of integers. You should be > able to just call DECODE-TIMEOUT using the TIMEOUT argument -- though > it might be better to DECLAIM the FTYPE of CONDITION-WAIT approriately > as well. Incorporated (and tested) the suggestion about making it a real. Does the following declamation look right? I've never made one before, so it'd be good if someone could check me please. (declaim (ftype (function ((unsigned-long) (unsigned-long) (real)) condition-wait))) (defun condition-wait (queue mutex &key timeout) ...) >> - ((1) (signal-deadline)) >> + ((1) (if timeout (return) (signal-deadline))) > > As discussed above. Similar code needed for the SB-LUTEX case as well. Confused, as above. I think you're suggesting I remove the "(if timeout (return)" part and require the calling code to handle the timeout? >> -CFLAGS = -g -Wall -Wsign-compare -O3 >> +CFLAGS = -g -Wall -Wsign-compare -O3 -D_GNU_SOURCE > > Since AFAIK this is only necessary for being able to build the lutex > code on Linux, I think this is probably better left out of the final > patch. (...but as John Fremlin noted just yesterday, we should really > be inhering CFLAGS from environment, or at least provide a way to > explicitly pass them to the build for things like defining > non-standard SBCL_HOME. Whatever you all think is best is fine by me. I anticipate that my "customers" will use the default build option (which incidentally is a small argument for enabling threads as the default build option, but I do not want to derail my own thread). >> + /* computation of timeout taken from pthread-futex.c */ >> + if (sec >= 0) { >> + ret = gettimeofday(&tv, NULL); >> + if (ret != 0) >> + return ret; >> + timeout.tv_sec = tv.tv_sec + sec + (tv.tv_usec + usec) / 1000000; >> + timeout.tv_nsec = (tv.tv_usec + usec) % 1000000; >> + } > > In and ideal world we might abstract this out, but as OAOO violations > and SBCL go this is pretty small. :) Agreed. > All in all, this is looking pretty good. The biggest thing missing are > test-cases. :) Some of the test-cases in tests/deadline.impure.lisp > should be enabled for SB-LUTEX when this code and the timeout > signalling is in place. I'm happy to add test cases as part of the patch. I think I'll add something to one of the sb-queue contribs? Just looking at the deadline.impure.lisp file, I'm a bit confused, because I haven't yet found the documentation for with-deadline. > (No, I didn't actually run any of this yet.) The tests that are already there broke when I did some things incorrectly, so we have some sort of assurance. I assume you'll want something other than an email to test a patch. I setup a git repository, so the cvs-export option should work? Thanks, David |
From: David L. R. <ra...@cs...> - 2009-12-21 00:30:29
|
Hi, Just a followup note below. --David >>> Another question concerns the return value of condition-wait when >>> there was a timeout. As of now, the lutex code returns 1. This is >>> slightly inconsistent with the current lutex behavior, where >>> condition-wait always returns 0, if it returns a value at all. Do we >>> care? It seems reasonable that the return value should be an >>> unreliable indicator for whether a condition variable was signaled >>> (for a reliable indicator, an object similar to CCL's >>> semaphore-notification-object [search for "ccl >>> make-semaphore-notification"] would be required). It looks to me like >>> waiting without a timeout on futexes and lutexes return different >>> values anyway. >> >> I think as long as we are living with deadlines in addition to local >> timeouts, the only right thing is to call (SIGNAL-DEADLINE) on >> timeout, because you easily cannot tell if the timeout was due to the >> local timeout or the global deadline. >> >> So code that _expects_ timeouts will look something like >> >> (handler-case (condition-wait ... :timeout 0.1) >> (timeout () (whatever-we-want-to-do-in-case-of-timeout)) > > I'm a bit confused as to what you mean by "local timeout" versus > "global deadline?" Does "global deadline" refer to functions similar > to the sb-impl:with-deadline that I see in tests/deadline.impure.lisp? > > My personal preference is to avoid this handler-case and instead (1) > use the return value as an estimate of whether the signal was received > and (2) a notification-object to know for certain. This > notification-object should probably be added in a different patch. > For all of my use cases, it doesn't matter whether the signal wasn't > received due to timeout or for some other reason (like the thread > being killed). If the signal was received, I do one thing; otherwise > I do another. Anyway, I think your answer to my question in the > previous paragraph will help address this concern. I better understand this issue now (playing around with "with-deadline" helped). I'll think about it some more, but I'd ideally like to remove the need to wrap the call to condition-wait with the handler. That being said, I have an interface built on top of condition-wait anyway, so I guess it doesn't really matter whether _my_ interface has to include a handler. The with-deadline feature strikes my relatively inexperienced brain as odd, but my patch should be consistent with it. |
From: Nikodemus S. <nik...@ra...> - 2009-12-23 09:43:57
|
2009/12/21 David L. Rager <ra...@cs...>: > One new thing I should mention: the time out of the lutexes varies a > lot. E.g, if I request a one second timeout, the lutex will timeout > after 0.91 seconds. If I request a 60 second timeout, it timesout > after 59.5 seconds. This strikes me as odd, but since an > approximation is good enough for my use case, I'm tempted to ignore > this issue for now. Interesting, and futexes give you tighter bounds? Low-priority issue anyways, but sounds like the pthread_cond_timedwait implementation isn't as good as one would like it to be. >>> My main question concerns interrupts. The futex code checks for >>> interrupts every 10 ms. Should I modify the lutex code to do the >>> same? I did not include the checking for now, based on the idea that >>> if such checks were necessary, it would have been in the lutex code in >>> the first place. >> >> No, what you did is fine. The futex code you looked at was probably >> the pthread-futex stuff, which emulates the Linux futex API on top of >> pthreads for lesser operating systems. The real futex code that gets >> used on Linux lives in src/runtime/linux-os.c. >> >> As long as we can, let the OS deal with the timeouts, since it can >> hopefully do a better job. > > Okay. > >>> Another question concerns the return value of condition-wait when >>> there was a timeout. As of now, the lutex code returns 1. This is >>> slightly inconsistent with the current lutex behavior, where >>> condition-wait always returns 0, if it returns a value at all. Do we >>> care? It seems reasonable that the return value should be an >>> unreliable indicator for whether a condition variable was signaled >>> (for a reliable indicator, an object similar to CCL's >>> semaphore-notification-object [search for "ccl >>> make-semaphore-notification"] would be required). It looks to me like >>> waiting without a timeout on futexes and lutexes return different >>> values anyway. >> >> I think as long as we are living with deadlines in addition to local >> timeouts, the only right thing is to call (SIGNAL-DEADLINE) on >> timeout, because you easily cannot tell if the timeout was due to the >> local timeout or the global deadline. >> >> So code that _expects_ timeouts will look something like >> >> (handler-case (condition-wait ... :timeout 0.1) >> (timeout () (whatever-we-want-to-do-in-case-of-timeout)) > > I'm a bit confused as to what you mean by "local timeout" versus > "global deadline?" Does "global deadline" refer to functions similar > to the sb-impl:with-deadline that I see in tests/deadline.impure.lisp? Yes - though it's SB-SYS:WITH-DEADLINE, and though SB-SYS is officially unsupported we have recommended people us it in favor of WITH-TIMEOUT due to fundamental unsafety of asynch interrupts. > My personal preference is to avoid this handler-case and instead (1) > use the return value as an estimate of whether the signal was received > and (2) a notification-object to know for certain. This > notification-object should probably be added in a different patch. > For all of my use cases, it doesn't matter whether the signal wasn't > received due to timeout or for some other reason (like the thread > being killed). If the signal was received, I do one thing; otherwise > I do another. Anyway, I think your answer to my question in the Hah, I see that the deadline design is careful enough to foresee this problem. The thing to do is (multiple-value-bind (to-sec to-usec stop-sec stop-usec deadlinep) (decode-timeout timeout) ...wait here... (if we-timed-out-p (if deadlinep (signal-deadline) (local-timeout-return-convention-if-any)) ...)) that is, the fifth return value of DECODE-TIMEOUT tells if you there was an outer WITH-DEADLINE that set a tighter bound than one from the local timeout argument. So in (defun server-loop (&key deadline) (loop (let ((client (accept-client))) (handler-case (with-deadline (:seconds timeout) (serve-client client)) (timeout () (log "client ~A timed out" client)))))) deep down the stack code can call CONDITION-WAIT with short timeouts, and as long as the global deadline has not been exceeded the SIGNAL-DEADLINE isn't called even if the waits time out. (I believe CCL's sempahore-notification-object is analogous to SBCL's semaphores.) > Incorporated (and tested) the suggestion about making it a real. Does > the following declamation look right? I've never made one before, so > it'd be good if someone could check me please. > > (declaim (ftype (function ((unsigned-long) (unsigned-long) (real)) > condition-wait))) Almost. :) The correct one would be along the lines of: (declaim (ftype (function (waitqueue mutex &key (:timeout (or null real))) t) condition-wait)) >>> - ((1) (signal-deadline)) >>> + ((1) (if timeout (return) (signal-deadline))) >> >> As discussed above. Similar code needed for the SB-LUTEX case as well. > > Confused, as above. I think you're suggesting I remove the "(if > timeout (return)" part and require the calling code to handle the > timeout? To correct myself, (as above...): use MULTIPLE-VALUE-BIND to get the fifth return value from DECODE-TIMEOUT and bind it to deadlinep, and the correct expression becomes (if deadlinep (signal-deadline) (return)) > I'm happy to add test cases as part of the patch. I think I'll add > something to one of the sb-queue contribs? Just looking at the Best places are tests/threads.pure.lisp and tests/threads.impure.lisp: "pure" files should only contain stuff that do not make any global changes, whereas "impure" files can use stuff like DEFUN as much as they like. Contrib tests should only test the contrib itself -- and as sb-queue doesn't use condition variables... > deadline.impure.lisp file, I'm a bit confused, because I haven't yet > found the documentation for with-deadline. (describe 'sb-sys:with-deadline) > incorrectly, so we have some sort of assurance. I assume you'll want > something other than an email to test a patch. I setup a git > repository, so the cvs-export option should work? Email is fine. A git repository to pull from is fine. (An email guarantees more immediate eyes on the code, though...) Since you're using git, patch from "git format-patch -1" as an attachment is very fine. (I think pretty much everyone here these days uses git for day-to-day SBCL work, and only uses CVS for the final commits -- and even that is liable to change to git sooner or later.) Cheers, -- Nikodemus |
From: David L. R. <ra...@cs...> - 2009-12-23 06:47:50
|
Hello, Does anyone know whether the test "symbol-value-in-thread.3" in tests/threads.pure.lisp should really be #+(and sb-thread (not sb-lutex))? The test hangs on me after (15000/200)*10 iterations, and I haven't yet been able to figure out why. The thought occurs to me, because Darwin could also use Lutexes? Thanks, David ===== Current status of the patch in case you're wondering ===== diff --git a/run-sbcl.sh b/run-sbcl.sh old mode 100644 new mode 100755 diff --git a/src/code/target-thread.lisp b/src/code/target-thread.lisp index ad83197..7f76d1b 100644 --- a/src/code/target-thread.lisp +++ b/src/code/target-thread.lisp @@ -213,7 +213,8 @@ created and old ones may exit at any time." int (lutex unsigned-long)) (define-alien-routine ("lutex_wait" %lutex-wait) - int (queue-lutex unsigned-long) (mutex-lutex unsigned-long)) + int (queue-lutex unsigned-long) (mutex-lutex unsigned-long) + (n long) (m unsigned-long)) (define-alien-routine ("lutex_wake" %lutex-wake) int (lutex unsigned-long) (n int)) @@ -520,17 +521,22 @@ IF-NOT-OWNER is :FORCE)." :structure waitqueue :slot data) -(defun condition-wait (queue mutex) +;(declaim (ftype (function (integer integer float) integer) +; condition-wait)) + +(defun condition-wait (queue mutex &key timeout) #!+sb-doc "Atomically release MUTEX and enqueue ourselves on QUEUE. Another thread may subsequently notify us using CONDITION-NOTIFY, at which -time we reacquire MUTEX and return to the caller." +time we reacquire MUTEX and return to the caller. TIMEOUT is specified +in seconds." #!-sb-thread (declare (ignore queue)) (assert mutex) #!-sb-thread (error "Not supported in unithread builds.") #!+sb-thread (let ((me *current-thread*)) (assert (eq me (mutex-%owner mutex))) + (assert (or (null timeout) (typep timeout 'real))) (/show0 "CONDITION-WAITing") #!+sb-lutex ;; Need to disable interrupts so that we don't miss setting the @@ -540,10 +546,18 @@ time we reacquire MUTEX and return to the caller." (unwind-protect (progn (setf (mutex-%owner mutex) nil) - (with-lutex-address (queue-lutex-address (waitqueue-lutex queue)) - (with-lutex-address (mutex-lutex-address (mutex-lutex mutex)) - (with-local-interrupts - (%lutex-wait queue-lutex-address mutex-lutex-address))))) + (multiple-value-bind (to-sec to-usec) (decode-timeout timeout) + (with-lutex-address (queue-lutex-address (waitqueue-lutex queue)) + (with-lutex-address (mutex-lutex-address (mutex-lutex mutex)) + (with-local-interrupts + (case (%lutex-wait queue-lutex-address + mutex-lutex-address + ;; our way if saying "no + ;; timeout": + (or to-sec -1) + (or to-usec 0)) + ((1) (signal-deadline)) + (otherwise t))))))) (setf (mutex-%owner mutex) me))) #!-sb-lutex ;; Need to disable interrupts so that we don't miss grabbing the @@ -556,7 +570,7 @@ time we reacquire MUTEX and return to the caller." ;; continuing after a deadline or EINTR. (setf (waitqueue-data queue) me) (loop - (multiple-value-bind (to-sec to-usec) (decode-timeout nil) + (multiple-value-bind (to-sec to-usec) (decode-timeout timeout) (case (unwind-protect (with-pinned-objects (queue me) ;; RELEASE-MUTEX is purposefully as close to diff --git a/src/runtime/GNUmakefile b/src/runtime/GNUmakefile index cfaac20..70d9d68 100644 --- a/src/runtime/GNUmakefile +++ b/src/runtime/GNUmakefile @@ -23,7 +23,7 @@ NM = nm -gp DEPEND_FLAGS = -MM GREP = grep -CFLAGS = -g -Wall -Wsign-compare -O3 +CFLAGS = -g -Wall -Wsign-compare -O3 -D_GNU_SOURCE ASFLAGS = $(CFLAGS) CPPFLAGS = -I. diff --git a/src/runtime/pthread-lutex.c b/src/runtime/pthread-lutex.c index 6365214..57a03bf 100644 --- a/src/runtime/pthread-lutex.c +++ b/src/runtime/pthread-lutex.c @@ -93,14 +93,35 @@ lutex_init (tagged_lutex_t tagged_lutex) } int -lutex_wait (tagged_lutex_t tagged_queue_lutex, tagged_lutex_t tagged_mutex_lutex) +lutex_wait (tagged_lutex_t tagged_queue_lutex, tagged_lutex_t tagged_mutex_lutex, + long sec, unsigned long usec) { int ret; struct lutex *queue_lutex = (struct lutex*) native_pointer(tagged_queue_lutex); struct lutex *mutex_lutex = (struct lutex*) native_pointer(tagged_mutex_lutex); + struct timeval tv; + struct timespec timeout; + + /* computation of timeout taken from pthread-futex.c */ + if (sec >= 0) { + ret = gettimeofday(&tv, NULL); + if (ret != 0) + return ret; + timeout.tv_sec = tv.tv_sec + sec + (tv.tv_usec + usec) / 1000000; + timeout.tv_nsec = (tv.tv_usec + usec) % 1000000; + } - ret = pthread_cond_wait(queue_lutex->condition_variable, mutex_lutex->mutex); - lutex_assert(ret == 0); + if (sec >= 0) { + ret = pthread_cond_timedwait(queue_lutex->condition_variable, + mutex_lutex->mutex, &timeout); + } else { + ret = pthread_cond_wait(queue_lutex->condition_variable, + mutex_lutex->mutex); + } + + lutex_assert(ret == 0 || ret == ETIMEDOUT); + if (ret == ETIMEDOUT) + return 1; return ret; } diff --git a/tests/deadline.impure.lisp b/tests/deadline.impure.lisp index 10bae09..b071dba 100644 --- a/tests/deadline.impure.lisp +++ b/tests/deadline.impure.lisp @@ -7,7 +7,6 @@ ,ok))) (error "No timeout from form:~% ~S" ',form))))) - (assert-timeout (sb-sys:with-deadline (:seconds 1) (run-program "sleep" '("3") :search t :wait t))) @@ -39,6 +38,13 @@ (assert (plusp n)) (assert (not final))) +#+sb-thread +(progn + (let ((sem (sb-thread::make-semaphore :count 0))) + (assert-timeout + (sb-impl::with-deadline (:seconds 1) + (sb-thread::wait-on-semaphore sem))))) + #+(and sb-thread (not sb-lutex)) (progn (assert-timeout @@ -53,11 +59,6 @@ (sb-thread:get-mutex lock)))) (assert-timeout - (let ((sem (sb-thread::make-semaphore :count 0))) - (sb-impl::with-deadline (:seconds 1) - (sb-thread::wait-on-semaphore sem)))) - - (assert-timeout (sb-impl::with-deadline (:seconds 1) (sb-thread:join-thread (sb-thread:make-thread (lambda () (loop (sleep 1))))))) diff --git a/tests/run-tests.sh b/tests/run-tests.sh old mode 100644 new mode 100755 diff --git a/tests/threads.impure.lisp b/tests/threads.impure.lisp index 3eb0fe0..588674c 100644 --- a/tests/threads.impure.lisp +++ b/tests/threads.impure.lisp @@ -306,6 +306,28 @@ (condition-notify queue)) (sleep 1))) +(let ((queue (make-waitqueue :name "queue")) + (lock (make-mutex :name "lock"))) + (labels ((in-new-thread () + (with-recursive-lock (lock) + (condition-wait queue lock :timeout 300) + (assert (eq *current-thread* (mutex-value lock)))))) + (make-thread #'in-new-thread) + (sleep 2) ; give it a chance to start + (with-recursive-lock (lock) + (condition-notify queue)) + (sleep 1))) + +(defmacro raises-timeout-p (&body body) + `(handler-case (progn (progn ,@body) nil) + (sb-ext:timeout () t))) + +(let ((queue (make-waitqueue :name "queue")) + (lock (make-mutex :name "lock"))) + (with-recursive-lock (lock) + (assert (raises-timeout-p + (condition-wait queue lock :timeout 1.1))))) + (let ((mutex (make-mutex :name "contended"))) (labels ((run () (let ((me *current-thread*)) @@ -322,10 +344,6 @@ ;;; semaphores -(defmacro raises-timeout-p (&body body) - `(handler-case (progn (progn ,@body) nil) - (sb-ext:timeout () t))) - (with-test (:name (:semaphore :wait-forever)) (let ((sem (make-semaphore :count 0))) (assert (raises-timeout-p diff --git a/tests/threads.pure.lisp b/tests/threads.pure.lisp index 8bfeea8..98bf543 100644 --- a/tests/threads.pure.lisp +++ b/tests/threads.pure.lisp @@ -52,8 +52,7 @@ ;;; Condition-wait should not be interruptible under WITHOUT-INTERRUPTS #+sb-thread -(with-test (:name without-interrupts+condition-wait - :fails-on :sb-lutex) +(with-test (:name without-interrupts+condition-wait) (let* ((lock (make-mutex)) (queue (make-waitqueue)) (thread (make-thread (lambda () |
From: Nikodemus S. <nik...@ra...> - 2009-12-23 09:49:52
|
> Does anyone know whether the test "symbol-value-in-thread.3" in > tests/threads.pure.lisp should really be #+(and sb-thread (not > sb-lutex))? The test hangs on me after (15000/200)*10 iterations, and > I haven't yet been able to figure out why. The thought occurs to me, > because Darwin could also use Lutexes? You are right, it probably should be predicated on :SB-LUTEX instead of :DARWIN. Cheers, -- Nikodemus |
From: David L. R. <ra...@cs...> - 2009-12-26 16:38:06
|
Hello Again, I've run into an testing issue WRT filesys.pure.lisp. It can't make it past the second test, because I'm receiving an error about "octet sequence 1 cannot be decoded." Is there something routine in the build/testing system that can cause such an error (I've tried clean.sh, but that didn't fix it)? At this point, I've duplicated the test failure on two or three different modified git clones, so I'd be a little surprised it it was related to git. I've also tried running sbcl from both bash and tcsh, in the hopes that it would be related to the environment variables that plagued stumpwm, but to no luck. The transcript is below the signature. Also, here's the lastest diff of the patch for adding a time out to condition variables: http://www.cs.utexas.edu/users/ragerdl/gitdiff.txt Thanks, David ;; the forms at the top are from test-util.lisp ;; the forms at the bottom are from filesys.pure.lisp lhug-7.cs.utexas.edu:/projects/hvg/ragerdl/hvg2/lisps/sbcl-git/tests$ ../run-sbcl.sh (running SBCL from: /projects/hvg/ragerdl/hvg2/lisps/sbcl-git/tests) This is SBCL 1.0.33.30, an implementation of ANSI Common Lisp. More information about SBCL is available at <http://www.sbcl.org/>. SBCL is free software, provided as is, with absolutely no warranty. It is mostly in the public domain; some portions are provided under BSD-style licenses. See the CREDITS and COPYING files in the distribution for more information. * (defpackage :test-util (:use :cl :sb-ext) (:export #:with-test #:report-test-status #:*failures* #:really-invoke-debugger #:*break-on-failure* #:*break-on-expected-failure*)) (in-package :test-util) (defvar *test-count* 0) (defvar *test-file* nil) (defvar *failures* nil) (defvar *break-on-failure* nil) (defvar *break-on-expected-failure* nil) (defun log-msg (&rest args) (format *trace-output* "~&::: ") (apply #'format *trace-output* args) (terpri *trace-output*) (force-output *trace-output*)) (defmacro with-test ((&key fails-on name) &body body) (let ((block-name (gensym))) `(block ,block-name (handler-bind ((error (lambda (error) (if (expected-failure-p ,fails-on) (fail-test :expected-failure ',name error) (fail-test :unexpected-failure ',name error)) (return-from ,block-name)))) (progn (log-msg "Running ~S" ',name) (start-test) ,@body (if (expected-failure-p ,fails-on) (fail-test :unexpected-success ',name nil) (log-msg "Success ~S" ',name))))))) (defun report-test-status () (with-standard-io-syntax (with-open-file (stream "test-status.lisp-expr" :direction :output :if-exists :supersede) (format stream "~s~%" *failures*)))) (defun start-test () (unless (eq *test-file* *load-pathname*) (setf *test-file* *load-pathname*) (setf *test-count* 0)) (incf *test-count*)) (defun fail-test (type test-name condition) (log-msg "~A ~S" type test-name) (push (list type *test-file* (or test-name *test-count*)) *failures*) (when (or (and *break-on-failure* (not (eq type :expected-failure))) *break-on-expected-failure*) (really-invoke-debugger condition))) (defun expected-failure-p (fails-on) (sb-impl::featurep fails-on)) (defun really-invoke-debugger (condition) (with-simple-restart (continue "Continue") (let ((*invoke-debugger-hook* *invoke-debugger-hook*)) (enable-debugger) (invoke-debugger condition)))) #<PACKAGE "TEST-UTIL"> * #<PACKAGE "TEST-UTIL"> * *TEST-COUNT* * *TEST-FILE* * *FAILURES* * *BREAK-ON-FAILURE* * *BREAK-ON-EXPECTED-FAILURE* * LOG-MSG * WITH-TEST * REPORT-TEST-STATUS * START-TEST * ; in: LAMBDA NIL ; (TEST-UTIL:REALLY-INVOKE-DEBUGGER CONDITION) ; ; caught STYLE-WARNING: ; undefined function: REALLY-INVOKE-DEBUGGER ; ; compilation unit finished ; Undefined function: ; REALLY-INVOKE-DEBUGGER ; caught 1 STYLE-WARNING condition FAIL-TEST * EXPECTED-FAILURE-P * REALLY-INVOKE-DEBUGGER * (in-package "CL-USER") #<PACKAGE "COMMON-LISP-USER"> * (let ((pathname0 (make-pathname :host nil :directory (pathname-directory *default-pathname-defaults*) :name "getty")) (pathname1 (make-pathname :host nil :directory nil :name nil))) (assert (equal (file-namestring pathname0) "getty")) (assert (equal (directory-namestring pathname0) (directory-namestring *default-pathname-defaults*))) (assert (equal (file-namestring pathname1) "")) (assert (equal (directory-namestring pathname1) ""))) NIL * (let ((dir (directory "../**/*.*"))) ;; We know a little bit about the structure of this result; ;; let's test to make sure that this test file is in it. (assert (find-if (lambda (pathname) (search #-win32 "tests/filesys.pure.lisp" #+win32 "tests\\filesys.pure.lisp" (namestring pathname))) dir))) debugger invoked on a SB-INT:C-STRING-DECODING-ERROR in thread #<THREAD "initial thread" RUNNING {1002ABA431}>: c-string decoding error (:external-format :ASCII): the octet sequence 1 cannot be decoded. Type HELP for debugger help, or (SB-EXT:QUIT) to exit from SBCL. restarts (invokable by number or by possibly-abbreviated name): 0: [ABORT] Exit debugger, returning to top level. (SB-INT:C-STRING-DECODING-ERROR :ASCII 1) 0] |
From: Gábor M. <me...@re...> - 2009-12-29 04:47:36
|
On Saturday 26 December 2009, David L. Rager wrote: > debugger invoked on a SB-INT:C-STRING-DECODING-ERROR in thread > #<THREAD > > "initial thread" RUNNING > > {1002ABA431}>: c-string decoding error (:external-format :ASCII): > the octet sequence 1 cannot be decoded. > > Type HELP for debugger help, or (SB-EXT:QUIT) to exit from SBCL. > > restarts (invokable by number or by possibly-abbreviated name): > 0: [ABORT] Exit debugger, returning to top level. > > (SB-INT:C-STRING-DECODING-ERROR :ASCII 1) > 0] Maybe a backtrace would help here? The patch looks fine to me. Gabor |
From: David L. R. <ra...@cs...> - 2009-12-31 04:05:42
|
Hello Again, Thanks for the feedback on the patch. The backtrace follows, including the session transcript. There were two inputs to the session: test-utils.lisp, and the first three forms in filesys.pure.lisp. This breakage still makes no sense to me. It's the default threaded version of SBCL built on Ubuntu, which should use futexes defined in target-thread.lisp and linux-os.c. I think I had the same problem with the lutex version. I'll keep looking at it, though I expect to not really get back into it until after the 10th or so. Thanks, David lhug-7.cs.utexas.edu:/projects/hvg/ragerdl/hvg2/lisps/sbcl-git/tests$ ../run-sbcl.sh (running SBCL from: /projects/hvg/ragerdl/hvg2/lisps/sbcl-git/tests) This is SBCL 1.0.34.2, an implementation of ANSI Common Lisp. More information about SBCL is available at <http://www.sbcl.org/>. SBCL is free software, provided as is, with absolutely no warranty. It is mostly in the public domain; some portions are provided under BSD-style licenses. See the CREDITS and COPYING files in the distribution for more information. * (defpackage :test-util (:use :cl :sb-ext) (:export #:with-test #:report-test-status #:*failures* #:really-invoke-debugger #:*break-on-failure* #:*break-on-expected-failure*)) (in-package :test-util) (defvar *test-count* 0) (defvar *test-file* nil) (defvar *failures* nil) (defvar *break-on-failure* nil) (defvar *break-on-expected-failure* nil) (defun log-msg (&rest args) (format *trace-output* "~&::: ") (apply #'format *trace-output* args) (terpri *trace-output*) (force-output *trace-output*)) (defmacro with-test ((&key fails-on name) &body body) (let ((block-name (gensym))) `(block ,block-name (handler-bind ((error (lambda (error) (if (expected-failure-p ,fails-on) (fail-test :expected-failure ',name error) (fail-test :unexpected-failure ',name error)) (return-from ,block-name)))) (progn (log-msg "Running ~S" ',name) (start-test) ,@body (if (expected-failure-p ,fails-on) (fail-test :unexpected-success ',name nil) (log-msg "Success ~S" ',name))))))) (defun report-test-status () (with-standard-io-syntax (with-open-file (stream "test-status.lisp-expr" :direction :output :if-exists :supersede) (format stream "~s~%" *failures*)))) (defun start-test () (unless (eq *test-file* *load-pathname*) (setf *test-file* *load-pathname*) (setf *test-count* 0)) (incf *test-count*)) (defun fail-test (type test-name condition) (log-msg "~A ~S" type test-name) (push (list type *test-file* (or test-name *test-count*)) *failures*) (when (or (and *break-on-failure* (not (eq type :expected-failure))) *break-on-expected-failure*) (really-invoke-debugger condition))) (defun expected-failure-p (fails-on) (sb-impl::featurep fails-on)) (defun really-invoke-debugger (condition) (with-simple-restart (continue "Continue") (let ((*invoke-debugger-hook* *invoke-debugger-hook*)) (enable-debugger) (invoke-debugger condition)))) #<PACKAGE "TEST-UTIL"> * #<PACKAGE "TEST-UTIL"> * *TEST-COUNT* * *TEST-FILE* * *FAILURES* * *BREAK-ON-FAILURE* * *BREAK-ON-EXPECTED-FAILURE* * LOG-MSG * WITH-TEST * REPORT-TEST-STATUS * START-TEST * ; in: LAMBDA NIL ; (TEST-UTIL:REALLY-INVOKE-DEBUGGER CONDITION) ; ; caught STYLE-WARNING: ; undefined function: REALLY-INVOKE-DEBUGGER ; ; compilation unit finished ; Undefined function: ; REALLY-INVOKE-DEBUGGER ; caught 1 STYLE-WARNING condition FAIL-TEST * EXPECTED-FAILURE-P * REALLY-INVOKE-DEBUGGER * (in-package "CL-USER") ;;; In sbcl-0.6.9 FOO-NAMESTRING functions returned "" instead of NIL. (let ((pathname0 (make-pathname :host nil :directory (pathname-directory *default-pathname-defaults*) :name "getty")) (pathname1 (make-pathname :host nil :directory nil :name nil))) (assert (equal (file-namestring pathname0) "getty")) (assert (equal (directory-namestring pathname0) (directory-namestring *default-pathname-defaults*))) (assert (equal (file-namestring pathname1) "")) (assert (equal (directory-namestring pathname1) ""))) ;;; In sbcl-0.6.9 DIRECTORY failed on paths with :WILD or ;;; :WILD-INFERIORS in their directory components. (let ((dir (directory "../**/*.*"))) ;; We know a little bit about the structure of this result; ;; let's test to make sure that this test file is in it. (assert (find-if (lambda (pathname) (search #-win32 "tests/filesys.pure.lisp" #+win32 "tests\\filesys.pure.lisp" (namestring pathname))) dir))) #<PACKAGE "COMMON-LISP-USER"> * NIL * debugger invoked on a SB-INT:C-STRING-DECODING-ERROR in thread #<THREAD "initial thread" RUNNING {1002ABA431}>: c-string decoding error (:external-format :ASCII): the octet sequence 1 cannot be decoded. Type HELP for debugger help, or (SB-EXT:QUIT) to exit from SBCL. restarts (invokable by number or by possibly-abbreviated name): 0: [ABORT] Exit debugger, returning to top level. (SB-INT:C-STRING-DECODING-ERROR :ASCII 1) 0] backtrace 0: (SB-INT:C-STRING-DECODING-ERROR :ASCII 1) 1: (SB-IMPL::READ-FROM-C-STRING/ASCII #.(SB-SYS:INT-SAP #X0053643B) CHARACTER) 2: ((FLET SB-IMPL::ONE-ITER)) 3: ((FLET SB-IMPL::ITERATE) #<CLOSURE (FLET SB-IMPL::ONE-ITER) {7FFFF56C84F9}>) 4: (SB-IMPL::CALL-WITH-NATIVE-DIRECTORY-ITERATOR #<CLOSURE (FLET SB-IMPL::ITERATE) {7FFFF56C85D9}> "/v/filer4b/v8q001/lisps/sbcl-git/" NIL) 5: (SB-IMPL::MAP-DIRECTORY #<CLOSURE (LAMBDA #) {1002F914D9}> #P"/v/filer4b/v8q001/lisps/sbcl-git/")[:EXTERNAL] 6: (SB-IMPL::MAP-WILD-INFERIORS #<CLOSURE (LAMBDA #) {1002F91369}> #<unavailable argument> #P"/v/filer4b/v8q001/lisps/sbcl-git/") 7: (SB-IMPL::MAP-MATCHING-DIRECTORIES #<CLOSURE (LAMBDA #) {1002F91369}> #P"/v/filer4b/v8q001/lisps/sbcl-git/**/*.*") 8: (DIRECTORY "../**/*.*")[:EXTERNAL] 9: ((LAMBDA ())) 10: (SB-INT:SIMPLE-EVAL-IN-LEXENV (LET ((DIR (DIRECTORY "../**/*.*"))) (ASSERT (FIND-IF (LAMBDA (PATHNAME) (SEARCH "tests/filesys.pure.lisp" #)) DIR))) #<NULL-LEXENV>) 11: (INTERACTIVE-EVAL (LET ((DIR (DIRECTORY "../**/*.*"))) (ASSERT (FIND-IF (LAMBDA (PATHNAME) (SEARCH "tests/filesys.pure.lisp" #)) DIR))))[:EXTERNAL] 12: (SB-IMPL::REPL-FUN NIL) 13: ((LAMBDA ())) 14: (SB-IMPL::%WITH-REBOUND-IO-SYNTAX #<CLOSURE (LAMBDA #) {1002AC0969}>) 15: (SB-IMPL::TOPLEVEL-REPL NIL) 16: (SB-IMPL::TOPLEVEL-INIT) 17: ((LABELS SB-IMPL::RESTART-LISP)) 0] list-locals SB-DEBUG::ARG-0 = :ASCII SB-DEBUG::ARG-1 = 1 0] |
From: Andy H. <ah...@gm...> - 2009-12-31 07:53:37
|
2009/12/31 David L. Rager <ra...@cs...>: > (SB-INT:C-STRING-DECODING-ERROR :ASCII 1) > 0] backtrace > > 0: (SB-INT:C-STRING-DECODING-ERROR :ASCII 1) > 1: (SB-IMPL::READ-FROM-C-STRING/ASCII #.(SB-SYS:INT-SAP #X0053643B) CHARACTER) > 2: ((FLET SB-IMPL::ONE-ITER)) > 3: ((FLET SB-IMPL::ITERATE) #<CLOSURE (FLET SB-IMPL::ONE-ITER) {7FFFF56C84F9}>) > 4: (SB-IMPL::CALL-WITH-NATIVE-DIRECTORY-ITERATOR > #<CLOSURE (FLET SB-IMPL::ITERATE) {7FFFF56C85D9}> > "/v/filer4b/v8q001/lisps/sbcl-git/" > NIL) Are there any files with unusual names (containing non-ASCII characters) in your sbcl-git directory? This looks like a typical case of cl:directory choking on a filename it doesn't like. From a normal SBCL repl, in the sbcl-git directory, does (directory "**/*") work? |
From: David L. R. <ra...@cs...> - 2009-12-31 08:24:45
|
That was exactly it, Andy. Thanks! On Thu, Dec 31, 2009 at 1:53 AM, Andy Hefner <ah...@gm...> wrote: > 2009/12/31 David L. Rager <ra...@cs...>: > >> (SB-INT:C-STRING-DECODING-ERROR :ASCII 1) >> 0] backtrace >> >> 0: (SB-INT:C-STRING-DECODING-ERROR :ASCII 1) >> 1: (SB-IMPL::READ-FROM-C-STRING/ASCII #.(SB-SYS:INT-SAP #X0053643B) CHARACTER) >> 2: ((FLET SB-IMPL::ONE-ITER)) >> 3: ((FLET SB-IMPL::ITERATE) #<CLOSURE (FLET SB-IMPL::ONE-ITER) {7FFFF56C84F9}>) >> 4: (SB-IMPL::CALL-WITH-NATIVE-DIRECTORY-ITERATOR >> #<CLOSURE (FLET SB-IMPL::ITERATE) {7FFFF56C85D9}> >> "/v/filer4b/v8q001/lisps/sbcl-git/" >> NIL) > > Are there any files with unusual names (containing non-ASCII > characters) in your sbcl-git directory? This looks like a typical case > of cl:directory choking on a filename it doesn't like. From a normal > SBCL repl, in the sbcl-git directory, does (directory "**/*") work? > |
From: David L. R. <ra...@cs...> - 2010-01-01 00:40:07
|
Greetings, I now have a proposed patch for adding the keyword parameter ":timeout" to the SBCL function condition-wait. This patch can be viewed at the following link. I'll also include it below the signature so that it can be archived on the email list. http://www.cs.utexas.edu/users/ragerdl/git-diff.txt The patch includes: (1) The timeout functionality implemented for both futexes and lutexes. (2) Modified documentation for condition-wait. I also standardized the return value of condition-wait. I deemed this to be a reasonable thing to do, because the lutex and futex versions were already returning different values (the futex version returned nil, while the lutex version returned 0). Feel free to reword the documentation about the return value being unreliable. I'm actually half convinced that the return value might be reliable, but I haven't thought about the issue enough to make such a promise. (3) A new test that uses the timeout parameter (4) Modified version of prior tests. This includes changing a test that should have been predicated on sb-lutex from darwin to sb-lutex. I also changed a test that previously failed on sb-lutex to now passing (you might want to review the change of that test, as perhaps it should have been dictated to fail on darwin instead of sb-lutex). (5) Modifications to the GNUMakefile and two shell script permissions. Please do not include these modifications, as they're just an artifact of the process, and I'd rather leave them in the automatically generated diff than remove them manually. I compiled and tested these changes using the make.sh and run-tests.sh scripts. I ran these with sb-thread enabled for both lutexes and futexes. Additionally, I successfully ran these scripts with no features at all (i.e., not even sb-thread). Nikodemus, Gábor, and Andy have my thanks for helping me with random issues and their thoughtful suggestions. Sorry about not providing a format-patch like suggested, but I've made about 20 local commits, and the pulls from the main repository are included in those, so that presentation of the patch is rather muddled. Thanks, David diff --git a/run-sbcl.sh b/run-sbcl.sh old mode 100644 new mode 100755 diff --git a/src/code/target-thread.lisp b/src/code/target-thread.lisp index ad83197..a8d68d5 100644 --- a/src/code/target-thread.lisp +++ b/src/code/target-thread.lisp @@ -213,7 +213,8 @@ created and old ones may exit at any time." int (lutex unsigned-long)) (define-alien-routine ("lutex_wait" %lutex-wait) - int (queue-lutex unsigned-long) (mutex-lutex unsigned-long)) + int (queue-lutex unsigned-long) (mutex-lutex unsigned-long) + (n long) (m unsigned-long)) (define-alien-routine ("lutex_wake" %lutex-wake) int (lutex unsigned-long) (n int)) @@ -520,17 +521,25 @@ IF-NOT-OWNER is :FORCE)." :structure waitqueue :slot data) -(defun condition-wait (queue mutex) +(declaim (ftype (function (waitqueue mutex &key (:timeout (or null real))) t) + condition-wait)) + +(defun condition-wait (queue mutex &key timeout) #!+sb-doc "Atomically release MUTEX and enqueue ourselves on QUEUE. Another thread may subsequently notify us using CONDITION-NOTIFY, at which -time we reacquire MUTEX and return to the caller." +time we reacquire MUTEX and return to the caller. If specified, +TIMEOUT should be a real number that specifies the number of +seconds to wait before timing out. Condition-wait often returns T if +the signal was received and nil otherwise. One should not rely on the +extreme accuracy of this return value." #!-sb-thread (declare (ignore queue)) (assert mutex) #!-sb-thread (error "Not supported in unithread builds.") #!+sb-thread (let ((me *current-thread*)) (assert (eq me (mutex-%owner mutex))) + (assert (or (null timeout) (typep timeout 'real))) (/show0 "CONDITION-WAITing") #!+sb-lutex ;; Need to disable interrupts so that we don't miss setting the @@ -540,10 +549,20 @@ time we reacquire MUTEX and return to the caller." (unwind-protect (progn (setf (mutex-%owner mutex) nil) - (with-lutex-address (queue-lutex-address (waitqueue-lutex queue)) - (with-lutex-address (mutex-lutex-address (mutex-lutex mutex)) - (with-local-interrupts - (%lutex-wait queue-lutex-address mutex-lutex-address))))) + (multiple-value-bind (to-sec to-usec stop-sec stop-usec deadlinep) + (decode-timeout timeout) + (declare (ignore stop-sec stop-usec)) + (with-lutex-address (queue-lutex-address (waitqueue-lutex queue)) + (with-lutex-address (mutex-lutex-address (mutex-lutex mutex)) + (with-local-interrupts + (case (%lutex-wait queue-lutex-address + mutex-lutex-address + ;; our way if saying "no + ;; timeout": + (or to-sec -1) + (or to-usec 0)) + ((1) (if deadlinep (signal-deadline) nil)) + (otherwise t))))))) (setf (mutex-%owner mutex) me))) #!-sb-lutex ;; Need to disable interrupts so that we don't miss grabbing the @@ -556,7 +575,9 @@ time we reacquire MUTEX and return to the caller." ;; continuing after a deadline or EINTR. (setf (waitqueue-data queue) me) (loop - (multiple-value-bind (to-sec to-usec) (decode-timeout nil) + (multiple-value-bind (to-sec to-usec stop-sec stop-usec deadlinep) + (decode-timeout timeout) + (declare (ignore stop-sec stop-usec)) (case (unwind-protect (with-pinned-objects (queue me) ;; RELEASE-MUTEX is purposefully as close to @@ -585,12 +606,12 @@ time we reacquire MUTEX and return to the caller." ;; better than nothing. (allow-with-interrupts (get-mutex mutex))) ;; ETIMEDOUT - ((1) (signal-deadline)) + ((1) (if deadlinep (signal-deadline) (return nil))) ;; EINTR ((2)) ;; EWOULDBLOCK, -1 here, is the possible spurious wakeup ;; case. 0 is the normal wakeup. - (otherwise (return))))))))) + (otherwise (return t))))))))) (defun condition-notify (queue &optional (n 1)) #!+sb-doc diff --git a/src/runtime/GNUmakefile b/src/runtime/GNUmakefile index cfaac20..70d9d68 100644 --- a/src/runtime/GNUmakefile +++ b/src/runtime/GNUmakefile @@ -23,7 +23,7 @@ NM = nm -gp DEPEND_FLAGS = -MM GREP = grep -CFLAGS = -g -Wall -Wsign-compare -O3 +CFLAGS = -g -Wall -Wsign-compare -O3 -D_GNU_SOURCE ASFLAGS = $(CFLAGS) CPPFLAGS = -I. diff --git a/src/runtime/pthread-lutex.c b/src/runtime/pthread-lutex.c index 6365214..57a03bf 100644 --- a/src/runtime/pthread-lutex.c +++ b/src/runtime/pthread-lutex.c @@ -93,14 +93,35 @@ lutex_init (tagged_lutex_t tagged_lutex) } int -lutex_wait (tagged_lutex_t tagged_queue_lutex, tagged_lutex_t tagged_mutex_lutex) +lutex_wait (tagged_lutex_t tagged_queue_lutex, tagged_lutex_t tagged_mutex_lutex, + long sec, unsigned long usec) { int ret; struct lutex *queue_lutex = (struct lutex*) native_pointer(tagged_queue_lutex); struct lutex *mutex_lutex = (struct lutex*) native_pointer(tagged_mutex_lutex); + struct timeval tv; + struct timespec timeout; + + /* computation of timeout taken from pthread-futex.c */ + if (sec >= 0) { + ret = gettimeofday(&tv, NULL); + if (ret != 0) + return ret; + timeout.tv_sec = tv.tv_sec + sec + (tv.tv_usec + usec) / 1000000; + timeout.tv_nsec = (tv.tv_usec + usec) % 1000000; + } - ret = pthread_cond_wait(queue_lutex->condition_variable, mutex_lutex->mutex); - lutex_assert(ret == 0); + if (sec >= 0) { + ret = pthread_cond_timedwait(queue_lutex->condition_variable, + mutex_lutex->mutex, &timeout); + } else { + ret = pthread_cond_wait(queue_lutex->condition_variable, + mutex_lutex->mutex); + } + + lutex_assert(ret == 0 || ret == ETIMEDOUT); + if (ret == ETIMEDOUT) + return 1; return ret; } diff --git a/tests/deadline.impure.lisp b/tests/deadline.impure.lisp index 10bae09..925fe4b 100644 --- a/tests/deadline.impure.lisp +++ b/tests/deadline.impure.lisp @@ -7,7 +7,6 @@ ,ok))) (error "No timeout from form:~% ~S" ',form))))) - (assert-timeout (sb-sys:with-deadline (:seconds 1) (run-program "sleep" '("3") :search t :wait t))) @@ -39,6 +38,12 @@ (assert (plusp n)) (assert (not final))) +#+sb-thread +(let ((sem (sb-thread::make-semaphore :count 0))) + (assert-timeout + (sb-impl::with-deadline (:seconds 1) + (sb-thread::wait-on-semaphore sem)))) + #+(and sb-thread (not sb-lutex)) (progn (assert-timeout @@ -53,11 +58,6 @@ (sb-thread:get-mutex lock)))) (assert-timeout - (let ((sem (sb-thread::make-semaphore :count 0))) - (sb-impl::with-deadline (:seconds 1) - (sb-thread::wait-on-semaphore sem)))) - - (assert-timeout (sb-impl::with-deadline (:seconds 1) (sb-thread:join-thread (sb-thread:make-thread (lambda () (loop (sleep 1))))))) diff --git a/tests/run-tests.sh b/tests/run-tests.sh old mode 100644 new mode 100755 diff --git a/tests/threads.impure.lisp b/tests/threads.impure.lisp index 3eb0fe0..ebc2dea 100644 --- a/tests/threads.impure.lisp +++ b/tests/threads.impure.lisp @@ -306,6 +306,28 @@ (condition-notify queue)) (sleep 1))) +(let ((queue (make-waitqueue :name "queue")) + (lock (make-mutex :name "lock"))) + (labels ((in-new-thread () + (with-recursive-lock (lock) + (condition-wait queue lock :timeout 300) + (assert (eq *current-thread* (mutex-value lock)))))) + (make-thread #'in-new-thread) + (sleep 2) ; give it a chance to start + (with-recursive-lock (lock) + (condition-notify queue)) + (sleep 1))) + +(defmacro raises-timeout-p (&body body) + `(handler-case (progn (progn ,@body) nil) + (sb-ext:timeout () t))) + +(let ((queue (make-waitqueue :name "queue")) + (lock (make-mutex :name "lock"))) + (with-recursive-lock (lock) + (assert (not (raises-timeout-p + (condition-wait queue lock :timeout 1.1)))))) + (let ((mutex (make-mutex :name "contended"))) (labels ((run () (let ((me *current-thread*)) @@ -322,10 +344,6 @@ ;;; semaphores -(defmacro raises-timeout-p (&body body) - `(handler-case (progn (progn ,@body) nil) - (sb-ext:timeout () t))) - (with-test (:name (:semaphore :wait-forever)) (let ((sem (make-semaphore :count 0))) (assert (raises-timeout-p diff --git a/tests/threads.pure.lisp b/tests/threads.pure.lisp index bc2b94c..7448a0e 100644 --- a/tests/threads.pure.lisp +++ b/tests/threads.pure.lisp @@ -52,8 +52,7 @@ ;;; Condition-wait should not be interruptible under WITHOUT-INTERRUPTS #+sb-thread -(with-test (:name without-interrupts+condition-wait - :fails-on :sb-lutex) +(with-test (:name without-interrupts+condition-wait) (let* ((lock (make-mutex)) (queue (make-waitqueue)) (thread (make-thread (lambda () @@ -184,7 +183,7 @@ ;;; wich _appear_ to be caused by malloc() and free() not being thread safe: an ;;; interrupted malloc in one thread can apparently block a free in another. There ;;; are also some indications that pthread_mutex_lock is not re-entrant. -#+(and sb-thread (not darwin)) +#+(and sb-thread (not sb-lutex)) (with-test (:name symbol-value-in-thread.3) (let* ((parent *current-thread*) (semaphore (make-semaphore)) |
From: David L. R. <ra...@cs...> - 2010-01-13 21:32:08
|
Greetings, Is there something I can change about this timed-waiting patch so that it gains acceptance into the repository? Thanks! David On Thu, Dec 31, 2009 at 6:39 PM, David L. Rager <ra...@cs...> wrote: > Greetings, > > I now have a proposed patch for adding the keyword parameter > ":timeout" to the SBCL function condition-wait. This patch can be > viewed at the following link. I'll also include it below the > signature so that it can be archived on the email list. > > http://www.cs.utexas.edu/users/ragerdl/git-diff.txt > > The patch includes: > > (1) The timeout functionality implemented for both futexes and lutexes. > > (2) Modified documentation for condition-wait. I also standardized > the return value of condition-wait. I deemed this to be a reasonable > thing to do, because the lutex and futex versions were already > returning different values (the futex version returned nil, while the > lutex version returned 0). Feel free to reword the documentation > about the return value being unreliable. I'm actually half convinced > that the return value might be reliable, but I haven't thought about > the issue enough to make such a promise. > > (3) A new test that uses the timeout parameter > > (4) Modified version of prior tests. This includes changing a test > that should have been predicated on sb-lutex from darwin to sb-lutex. > I also changed a test that previously failed on sb-lutex to now > passing (you might want to review the change of that test, as perhaps > it should have been dictated to fail on darwin instead of sb-lutex). > > (5) Modifications to the GNUMakefile and two shell script permissions. > Please do not include these modifications, as they're just an > artifact of the process, and I'd rather leave them in the > automatically generated diff than remove them manually. > > I compiled and tested these changes using the make.sh and run-tests.sh > scripts. I ran these with sb-thread enabled for both lutexes and > futexes. Additionally, I successfully ran these scripts with no > features at all (i.e., not even sb-thread). > > Nikodemus, Gábor, and Andy have my thanks for helping me with random > issues and their thoughtful suggestions. Sorry about not providing a > format-patch like suggested, but I've made about 20 local commits, and > the pulls from the main repository are included in those, so that > presentation of the patch is rather muddled. > > Thanks, > David > > > diff --git a/run-sbcl.sh b/run-sbcl.sh > old mode 100644 > new mode 100755 > diff --git a/src/code/target-thread.lisp b/src/code/target-thread.lisp > index ad83197..a8d68d5 100644 > --- a/src/code/target-thread.lisp > +++ b/src/code/target-thread.lisp > @@ -213,7 +213,8 @@ created and old ones may exit at any time." > int (lutex unsigned-long)) > > (define-alien-routine ("lutex_wait" %lutex-wait) > - int (queue-lutex unsigned-long) (mutex-lutex unsigned-long)) > + int (queue-lutex unsigned-long) (mutex-lutex unsigned-long) > + (n long) (m unsigned-long)) > > (define-alien-routine ("lutex_wake" %lutex-wake) > int (lutex unsigned-long) (n int)) > @@ -520,17 +521,25 @@ IF-NOT-OWNER is :FORCE)." > :structure waitqueue > :slot data) > > -(defun condition-wait (queue mutex) > +(declaim (ftype (function (waitqueue mutex &key (:timeout (or null real))) t) > + condition-wait)) > + > +(defun condition-wait (queue mutex &key timeout) > #!+sb-doc > "Atomically release MUTEX and enqueue ourselves on QUEUE. Another > thread may subsequently notify us using CONDITION-NOTIFY, at which > -time we reacquire MUTEX and return to the caller." > +time we reacquire MUTEX and return to the caller. If specified, > +TIMEOUT should be a real number that specifies the number of > +seconds to wait before timing out. Condition-wait often returns T if > +the signal was received and nil otherwise. One should not rely on the > +extreme accuracy of this return value." > #!-sb-thread (declare (ignore queue)) > (assert mutex) > #!-sb-thread (error "Not supported in unithread builds.") > #!+sb-thread > (let ((me *current-thread*)) > (assert (eq me (mutex-%owner mutex))) > + (assert (or (null timeout) (typep timeout 'real))) > (/show0 "CONDITION-WAITing") > #!+sb-lutex > ;; Need to disable interrupts so that we don't miss setting the > @@ -540,10 +549,20 @@ time we reacquire MUTEX and return to the caller." > (unwind-protect > (progn > (setf (mutex-%owner mutex) nil) > - (with-lutex-address (queue-lutex-address (waitqueue-lutex queue)) > - (with-lutex-address (mutex-lutex-address (mutex-lutex mutex)) > - (with-local-interrupts > - (%lutex-wait queue-lutex-address mutex-lutex-address))))) > + (multiple-value-bind (to-sec to-usec stop-sec stop-usec deadlinep) > + (decode-timeout timeout) > + (declare (ignore stop-sec stop-usec)) > + (with-lutex-address (queue-lutex-address > (waitqueue-lutex queue)) > + (with-lutex-address (mutex-lutex-address (mutex-lutex mutex)) > + (with-local-interrupts > + (case (%lutex-wait queue-lutex-address > + mutex-lutex-address > + ;; our way if saying "no > + ;; timeout": > + (or to-sec -1) > + (or to-usec 0)) > + ((1) (if deadlinep (signal-deadline) nil)) > + (otherwise t))))))) > (setf (mutex-%owner mutex) me))) > #!-sb-lutex > ;; Need to disable interrupts so that we don't miss grabbing the > @@ -556,7 +575,9 @@ time we reacquire MUTEX and return to the caller." > ;; continuing after a deadline or EINTR. > (setf (waitqueue-data queue) me) > (loop > - (multiple-value-bind (to-sec to-usec) (decode-timeout nil) > + (multiple-value-bind (to-sec to-usec stop-sec stop-usec deadlinep) > + (decode-timeout timeout) > + (declare (ignore stop-sec stop-usec)) > (case (unwind-protect > (with-pinned-objects (queue me) > ;; RELEASE-MUTEX is purposefully as close to > @@ -585,12 +606,12 @@ time we reacquire MUTEX and return to the caller." > ;; better than nothing. > (allow-with-interrupts (get-mutex mutex))) > ;; ETIMEDOUT > - ((1) (signal-deadline)) > + ((1) (if deadlinep (signal-deadline) (return nil))) > ;; EINTR > ((2)) > ;; EWOULDBLOCK, -1 here, is the possible spurious wakeup > ;; case. 0 is the normal wakeup. > - (otherwise (return))))))))) > + (otherwise (return t))))))))) > > (defun condition-notify (queue &optional (n 1)) > #!+sb-doc > diff --git a/src/runtime/GNUmakefile b/src/runtime/GNUmakefile > index cfaac20..70d9d68 100644 > --- a/src/runtime/GNUmakefile > +++ b/src/runtime/GNUmakefile > @@ -23,7 +23,7 @@ NM = nm -gp > DEPEND_FLAGS = -MM > GREP = grep > > -CFLAGS = -g -Wall -Wsign-compare -O3 > +CFLAGS = -g -Wall -Wsign-compare -O3 -D_GNU_SOURCE > ASFLAGS = $(CFLAGS) > CPPFLAGS = -I. > > diff --git a/src/runtime/pthread-lutex.c b/src/runtime/pthread-lutex.c > index 6365214..57a03bf 100644 > --- a/src/runtime/pthread-lutex.c > +++ b/src/runtime/pthread-lutex.c > @@ -93,14 +93,35 @@ lutex_init (tagged_lutex_t tagged_lutex) > } > > int > -lutex_wait (tagged_lutex_t tagged_queue_lutex, tagged_lutex_t > tagged_mutex_lutex) > +lutex_wait (tagged_lutex_t tagged_queue_lutex, tagged_lutex_t > tagged_mutex_lutex, > + long sec, unsigned long usec) > { > int ret; > struct lutex *queue_lutex = (struct lutex*) > native_pointer(tagged_queue_lutex); > struct lutex *mutex_lutex = (struct lutex*) > native_pointer(tagged_mutex_lutex); > + struct timeval tv; > + struct timespec timeout; > + > + /* computation of timeout taken from pthread-futex.c */ > + if (sec >= 0) { > + ret = gettimeofday(&tv, NULL); > + if (ret != 0) > + return ret; > + timeout.tv_sec = tv.tv_sec + sec + (tv.tv_usec + usec) / 1000000; > + timeout.tv_nsec = (tv.tv_usec + usec) % 1000000; > + } > > - ret = pthread_cond_wait(queue_lutex->condition_variable, > mutex_lutex->mutex); > - lutex_assert(ret == 0); > + if (sec >= 0) { > + ret = pthread_cond_timedwait(queue_lutex->condition_variable, > + mutex_lutex->mutex, &timeout); > + } else { > + ret = pthread_cond_wait(queue_lutex->condition_variable, > + mutex_lutex->mutex); > + } > + > + lutex_assert(ret == 0 || ret == ETIMEDOUT); > + if (ret == ETIMEDOUT) > + return 1; > > return ret; > } > diff --git a/tests/deadline.impure.lisp b/tests/deadline.impure.lisp > index 10bae09..925fe4b 100644 > --- a/tests/deadline.impure.lisp > +++ b/tests/deadline.impure.lisp > @@ -7,7 +7,6 @@ > ,ok))) > (error "No timeout from form:~% ~S" ',form))))) > > - > (assert-timeout > (sb-sys:with-deadline (:seconds 1) > (run-program "sleep" '("3") :search t :wait t))) > @@ -39,6 +38,12 @@ > (assert (plusp n)) > (assert (not final))) > > +#+sb-thread > +(let ((sem (sb-thread::make-semaphore :count 0))) > + (assert-timeout > + (sb-impl::with-deadline (:seconds 1) > + (sb-thread::wait-on-semaphore sem)))) > + > #+(and sb-thread (not sb-lutex)) > (progn > (assert-timeout > @@ -53,11 +58,6 @@ > (sb-thread:get-mutex lock)))) > > (assert-timeout > - (let ((sem (sb-thread::make-semaphore :count 0))) > - (sb-impl::with-deadline (:seconds 1) > - (sb-thread::wait-on-semaphore sem)))) > - > - (assert-timeout > (sb-impl::with-deadline (:seconds 1) > (sb-thread:join-thread > (sb-thread:make-thread (lambda () (loop (sleep 1))))))) > diff --git a/tests/run-tests.sh b/tests/run-tests.sh > old mode 100644 > new mode 100755 > diff --git a/tests/threads.impure.lisp b/tests/threads.impure.lisp > index 3eb0fe0..ebc2dea 100644 > --- a/tests/threads.impure.lisp > +++ b/tests/threads.impure.lisp > @@ -306,6 +306,28 @@ > (condition-notify queue)) > (sleep 1))) > > +(let ((queue (make-waitqueue :name "queue")) > + (lock (make-mutex :name "lock"))) > + (labels ((in-new-thread () > + (with-recursive-lock (lock) > + (condition-wait queue lock :timeout 300) > + (assert (eq *current-thread* (mutex-value lock)))))) > + (make-thread #'in-new-thread) > + (sleep 2) ; give it a chance to start > + (with-recursive-lock (lock) > + (condition-notify queue)) > + (sleep 1))) > + > +(defmacro raises-timeout-p (&body body) > + `(handler-case (progn (progn ,@body) nil) > + (sb-ext:timeout () t))) > + > +(let ((queue (make-waitqueue :name "queue")) > + (lock (make-mutex :name "lock"))) > + (with-recursive-lock (lock) > + (assert (not (raises-timeout-p > + (condition-wait queue lock :timeout 1.1)))))) > + > (let ((mutex (make-mutex :name "contended"))) > (labels ((run () > (let ((me *current-thread*)) > @@ -322,10 +344,6 @@ > > ;;; semaphores > > -(defmacro raises-timeout-p (&body body) > - `(handler-case (progn (progn ,@body) nil) > - (sb-ext:timeout () t))) > - > (with-test (:name (:semaphore :wait-forever)) > (let ((sem (make-semaphore :count 0))) > (assert (raises-timeout-p > diff --git a/tests/threads.pure.lisp b/tests/threads.pure.lisp > index bc2b94c..7448a0e 100644 > --- a/tests/threads.pure.lisp > +++ b/tests/threads.pure.lisp > @@ -52,8 +52,7 @@ > ;;; Condition-wait should not be interruptible under WITHOUT-INTERRUPTS > > #+sb-thread > -(with-test (:name without-interrupts+condition-wait > - :fails-on :sb-lutex) > +(with-test (:name without-interrupts+condition-wait) > (let* ((lock (make-mutex)) > (queue (make-waitqueue)) > (thread (make-thread (lambda () > @@ -184,7 +183,7 @@ > ;;; wich _appear_ to be caused by malloc() and free() not being thread safe: an > ;;; interrupted malloc in one thread can apparently block a free in > another. There > ;;; are also some indications that pthread_mutex_lock is not re-entrant. > -#+(and sb-thread (not darwin)) > +#+(and sb-thread (not sb-lutex)) > (with-test (:name symbol-value-in-thread.3) > (let* ((parent *current-thread*) > (semaphore (make-semaphore)) > |
From: Christophe R. <cs...@ca...> - 2010-01-16 09:59:17
|
"David L. Rager" <ra...@cs...> writes: > Is there something I can change about this timed-waiting patch so that > it gains acceptance into the repository? Speaking for myself: my time at work and home is highly constrained, and probably will continue to be until April or May, and I can't spare the time to do a thorough job of reviewing work like this. My guess is that the same applies to many; it's one of the perils of a volunteer workforce. That is to say, don't take a lack of response as an active rejection; it is an unfortunate thing that at the moment there are not as many active resources to spend on SBCL maintenance and development as there once were (and hopefully there will be again). Cheers, Christophe |
From: Bruce O'N. <ec...@pc...> - 2010-01-21 11:13:37
|
Hi, Thanks for the note. I also had the same question. Thanks for all of your work on SBCL and I hope being busy at work is 'good busy'! cheers bruce ----- Message d'origine ----- De: Christophe Rhodes <cs...@ca...> Date: Sat, 16 Jan 2010 09:59:09 +0000 Sujet: [Sbcl-devel] current sbcl maintenance sluggishness (was Re: Timed Condition Variable/Semaphore Waiting) À: "David L. Rager" <ra...@cs...> Cc: sbc...@li... "David L. Rager" writes: > Is there something I can change about this timed-waiting patch so that > it gains acceptance into the repository? Speaking for myself: my time at work and home is highly constrained, and probably will continue to be until April or May, and I can't spare the time to do a thorough job of reviewing work like this. My guess is that the same applies to many; it's one of the perils of a volunteer workforce. That is to say, don't take a lack of response as an active rejection; it is an unfortunate thing that at the moment there are not as many active resources to spend on SBCL maintenance and development as there once were (and hopefully there will be again). Cheers, Christophe ------------------------------------------------------------------------------ Throughout its 18-year history, RSA Conference consistently attracts the world's best and brightest in the field, creating opportunities for Conference attendees to learn about information security's most important issues through interactions with peers, luminaries and emerging and established companies. http://p.sf.net/sfu/rsaconf-dev2dev _______________________________________________ Sbcl-devel mailing list Sbc...@li... https://lists.sourceforge.net/lists/listinfo/sbcl-devel |