117 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			Factor
		
	
	
		
			Executable File
		
	
			
		
		
	
	
			117 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			Factor
		
	
	
		
			Executable File
		
	
| ! Copyright (C) 2008 Slava Pestov.
 | |
| ! See http://factorcode.org/license.txt for BSD license.
 | |
| USING: dequeues dlists kernel threads continuations math
 | |
| concurrency.conditions ;
 | |
| IN: concurrency.locks
 | |
| 
 | |
| ! Simple critical sections
 | |
| TUPLE: lock threads owner reentrant? ;
 | |
| 
 | |
| : <lock> ( -- lock )
 | |
|     <dlist> f f lock boa ;
 | |
| 
 | |
| : <reentrant-lock> ( -- lock )
 | |
|     <dlist> f t lock boa ;
 | |
| 
 | |
| <PRIVATE
 | |
| 
 | |
| : acquire-lock ( lock timeout -- )
 | |
|     over lock-owner
 | |
|     [ 2dup >r lock-threads r> "lock" wait ] when drop
 | |
|     self swap set-lock-owner ;
 | |
| 
 | |
| : release-lock ( lock -- )
 | |
|     f over set-lock-owner
 | |
|     lock-threads notify-1 ;
 | |
| 
 | |
| : 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
 | |
| 
 | |
| PRIVATE>
 | |
| 
 | |
| : with-lock-timeout ( lock timeout quot -- )
 | |
|     pick lock-reentrant? [
 | |
|         pick lock-owner self eq? [
 | |
|             2nip call
 | |
|         ] [
 | |
|             (with-lock)
 | |
|         ] if
 | |
|     ] [
 | |
|         (with-lock)
 | |
|     ] if ; inline
 | |
| 
 | |
| : with-lock ( lock quot -- )
 | |
|     f swap with-lock-timeout ; inline
 | |
| 
 | |
| ! Many-reader/single-writer locks
 | |
| TUPLE: rw-lock readers writers reader# writer ;
 | |
| 
 | |
| : <rw-lock> ( -- lock )
 | |
|     <dlist> <dlist> 0 f rw-lock boa ;
 | |
| 
 | |
| <PRIVATE
 | |
| 
 | |
| : add-reader ( lock -- )
 | |
|     dup rw-lock-reader# 1+ swap set-rw-lock-reader# ;
 | |
| 
 | |
| : acquire-read-lock ( lock timeout -- )
 | |
|     over rw-lock-writer
 | |
|     [ 2dup >r rw-lock-readers r> "read lock" wait ] when drop
 | |
|     add-reader ;
 | |
| 
 | |
| : notify-writer ( lock -- )
 | |
|     rw-lock-writers notify-1 ;
 | |
| 
 | |
| : remove-reader ( lock -- )
 | |
|     dup rw-lock-reader# 1- swap set-rw-lock-reader# ;
 | |
| 
 | |
| : release-read-lock ( lock -- )
 | |
|     dup remove-reader
 | |
|     dup rw-lock-reader# zero? [ notify-writer ] [ drop ] if ;
 | |
| 
 | |
| : acquire-write-lock ( lock timeout -- )
 | |
|     over rw-lock-writer pick rw-lock-reader# 0 > or
 | |
|     [ 2dup >r rw-lock-writers r> "write lock" wait ] when drop
 | |
|     self swap set-rw-lock-writer ;
 | |
| 
 | |
| : release-write-lock ( lock -- )
 | |
|     f over set-rw-lock-writer
 | |
|     dup rw-lock-readers dequeue-empty?
 | |
|     [ notify-writer ] [ rw-lock-readers notify-all ] if ;
 | |
| 
 | |
| : reentrant-read-lock-ok? ( lock -- ? )
 | |
|     #! If we already have a write lock, then we can grab a read
 | |
|     #! lock too.
 | |
|     rw-lock-writer self eq? ;
 | |
| 
 | |
| : 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.
 | |
|     dup rw-lock-writer self eq?
 | |
|     swap rw-lock-reader# zero? and ;
 | |
| 
 | |
| PRIVATE>
 | |
| 
 | |
| : with-read-lock-timeout ( lock timeout quot -- )
 | |
|     pick reentrant-read-lock-ok? [
 | |
|         [ drop add-reader ] [ remove-reader ] do-lock
 | |
|     ] [
 | |
|         [ acquire-read-lock ] [ release-read-lock ] do-lock
 | |
|     ] if ; inline
 | |
| 
 | |
| : with-read-lock ( lock quot -- )
 | |
|     f swap with-read-lock-timeout ; inline
 | |
| 
 | |
| : with-write-lock-timeout ( lock timeout quot -- )
 | |
|     pick reentrant-write-lock-ok? [ 2nip call ] [
 | |
|         [ acquire-write-lock ] [ release-write-lock ] do-lock
 | |
|     ] if ; inline
 | |
| 
 | |
| : with-write-lock ( lock quot -- )
 | |
|     f swap with-write-lock-timeout ; inline
 |