factor/basis/concurrency/locks/locks.factor

116 lines
3.1 KiB
Factor
Raw Normal View History

2008-02-18 06:07:40 -05:00
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
2008-08-19 15:06:20 -04:00
USING: deques dlists kernel threads continuations math
2008-08-30 22:19:06 -04:00
concurrency.conditions combinators.short-circuit accessors ;
2008-02-18 06:07:40 -05:00
IN: concurrency.locks
! Simple critical sections
TUPLE: lock threads owner reentrant? ;
2008-02-18 06:07:40 -05:00
: <lock> ( -- lock )
<dlist> f f lock boa ;
: <reentrant-lock> ( -- lock )
<dlist> f t lock boa ;
2008-02-18 06:07:40 -05:00
<PRIVATE
2008-02-18 10:08:59 -05:00
: acquire-lock ( lock timeout -- )
2008-08-30 22:19:06 -04:00
over owner>>
[ 2dup >r threads>> r> "lock" wait ] when drop
self >>owner drop ;
2008-02-18 06:07:40 -05:00
: release-lock ( lock -- )
2008-08-30 22:19:06 -04:00
f >>owner
threads>> notify-1 ;
2008-02-18 06:07:40 -05:00
2008-02-18 10:08:59 -05:00
: do-lock ( lock timeout quot acquire release -- )
>r >r pick rot r> call ! use up timeout acquire
swap r> curry [ ] cleanup ; inline
: (with-lock) ( lock timeout quot -- )
[ acquire-lock ] [ release-lock ] do-lock ; inline
2008-02-18 06:07:40 -05:00
PRIVATE>
: with-lock-timeout ( lock timeout quot -- )
2008-08-30 22:19:06 -04:00
pick reentrant?>> [
pick owner>> self eq? [
2nip call
] [
(with-lock)
] if
] [
(with-lock)
] if ; inline
2008-02-18 06:07:40 -05:00
: with-lock ( lock quot -- )
f swap with-lock-timeout ; inline
2008-02-18 06:07:40 -05:00
! Many-reader/single-writer locks
TUPLE: rw-lock readers writers reader# writer ;
: <rw-lock> ( -- lock )
<dlist> <dlist> 0 f rw-lock boa ;
2008-02-18 06:07:40 -05:00
<PRIVATE
2008-03-01 02:57:34 -05:00
: add-reader ( lock -- )
2008-08-30 22:19:06 -04:00
[ 1+ ] change-reader# drop ;
2008-03-01 02:57:34 -05:00
: acquire-read-lock ( lock timeout -- )
2008-08-30 22:19:06 -04:00
over writer>>
[ 2dup >r readers>> r> "read lock" wait ] when drop
2008-03-01 02:57:34 -05:00
add-reader ;
2008-02-18 06:07:40 -05:00
: notify-writer ( lock -- )
2008-08-30 22:19:06 -04:00
writers>> notify-1 ;
2008-02-18 06:07:40 -05:00
2008-03-01 02:57:34 -05:00
: remove-reader ( lock -- )
2008-08-30 22:19:06 -04:00
[ 1- ] change-reader# drop ;
2008-03-01 02:57:34 -05:00
2008-02-18 06:07:40 -05:00
: release-read-lock ( lock -- )
2008-03-01 02:57:34 -05:00
dup remove-reader
2008-08-30 22:19:06 -04:00
dup reader#>> zero? [ notify-writer ] [ drop ] if ;
2008-02-18 06:07:40 -05:00
: acquire-write-lock ( lock timeout -- )
2008-08-30 22:19:06 -04:00
over writer>> pick reader#>> 0 > or
[ 2dup >r writers>> r> "write lock" wait ] when drop
self >>writer drop ;
2008-02-18 06:07:40 -05:00
: release-write-lock ( lock -- )
2008-08-30 22:19:06 -04:00
f >>writer
dup readers>> deque-empty?
[ notify-writer ] [ readers>> notify-all ] if ;
2008-02-18 06:07:40 -05:00
2008-03-01 02:57:34 -05:00
: reentrant-read-lock-ok? ( lock -- ? )
#! If we already have a write lock, then we can grab a read
#! lock too.
2008-08-30 22:19:06 -04:00
writer>> self eq? ;
2008-03-01 02:57:34 -05:00
: reentrant-write-lock-ok? ( lock -- ? )
#! The only case where we have a writer and > 1 reader is
#! write -> read re-entrancy, and in this case we prohibit
#! a further write -> read -> write re-entrancy.
2008-08-30 22:19:06 -04:00
{ [ writer>> self eq? ] [ reader#>> zero? ] } 1&& ;
2008-02-18 06:07:40 -05:00
PRIVATE>
: with-read-lock-timeout ( lock timeout quot -- )
2008-03-01 02:57:34 -05:00
pick reentrant-read-lock-ok? [
[ drop add-reader ] [ remove-reader ] do-lock
] [
2008-02-18 06:07:40 -05:00
[ acquire-read-lock ] [ release-read-lock ] do-lock
2008-03-01 02:57:34 -05:00
] if ; inline
2008-02-18 06:07:40 -05:00
: with-read-lock ( lock quot -- )
f swap with-read-lock-timeout ; inline
: with-write-lock-timeout ( lock timeout quot -- )
2008-03-01 02:57:34 -05:00
pick reentrant-write-lock-ok? [ 2nip call ] [
2008-02-18 06:07:40 -05:00
[ acquire-write-lock ] [ release-write-lock ] do-lock
2008-03-01 02:57:34 -05:00
] if ; inline
: with-write-lock ( lock quot -- )
f swap with-write-lock-timeout ; inline