diff options
author | Steve Bennett <steveb@workware.net.au> | 2019-07-29 13:28:31 +1000 |
---|---|---|
committer | Steve Bennett <steveb@workware.net.au> | 2019-07-31 08:46:01 +1000 |
commit | c8abda4d473268842201f228b8980e523766e91b (patch) | |
tree | e8563fd0694c51885bf0e4f504049c55c50e0f41 | |
parent | a8b8c416c7f3c9e06fe3320b25e8dd37570e9f92 (diff) | |
download | jimtcl-c8abda4d473268842201f228b8980e523766e91b.zip jimtcl-c8abda4d473268842201f228b8980e523766e91b.tar.gz jimtcl-c8abda4d473268842201f228b8980e523766e91b.tar.bz2 |
aio: Add support for lock -wait
Sometimes it is useful to wait for a lock to become available.
Signed-off-by: Steve Bennett <steveb@workware.net.au>
-rw-r--r-- | jim-aio.c | 16 | ||||
-rw-r--r-- | jim_tcl.txt | 20 | ||||
-rw-r--r-- | tests/lock.test | 13 |
3 files changed, 36 insertions, 13 deletions
@@ -1440,13 +1440,21 @@ static int aio_cmd_lock(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { AioFile *af = Jim_CmdPrivData(interp); struct flock fl; + int lockmode = F_SETLK; + + if (argc == 1) { + if (!Jim_CompareStringImmediate(interp, argv[0], "-wait")) { + return -1; + } + lockmode = F_SETLKW; + } fl.l_start = 0; fl.l_len = 0; fl.l_type = F_WRLCK; fl.l_whence = SEEK_SET; - switch (fcntl(af->fd, F_SETLK, &fl)) + switch (fcntl(af->fd, lockmode, &fl)) { case 0: Jim_SetResultInt(interp, 1); @@ -1732,12 +1740,12 @@ static const jim_subcmd_type aio_command_table[] = { }, #endif #if defined(HAVE_STRUCT_FLOCK) - { "lock", + { "lock ?-wait?", NULL, aio_cmd_lock, 0, - 0, - /* Description: Attempt to get a lock. */ + 1, + /* Description: Attempt to get a lock, possibly waiting */ }, { "unlock", NULL, diff --git a/jim_tcl.txt b/jim_tcl.txt index 77c4b35..247ad7e 100644 --- a/jim_tcl.txt +++ b/jim_tcl.txt @@ -56,6 +56,7 @@ Changes since 0.78 ~~~~~~~~~~~~~~~~~~ 1. Add `file mtimeus` for high resolution file timestamps 2. `aio` now supports datagram Unix-Domain sockets +3. Add support for `aio lock -wait` Changes between 0.77 and 0.78 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -4581,9 +4582,9 @@ aio +$handle *buffering none|line|full*+:: Sets the buffering mode of the stream. -+$handle *close* ?r(ead)|w(rite)|-nodelete?+:: ++$handle *close ?r(ead)|w(rite)|-nodelete?*+:: Closes the stream. - The +'read'+ and +'write'+ arguments perform a "half-close" on a socket. See the +shutdown(2)+ man page. + The +'read'+ and +'write'+ arguments perform a "half-close" on a socket. See the 'shutdown(2)' man page. The +'-nodelete'+ option is applicable only for Unix domain sockets. It closes the socket but does not delete the bound path (e.g. after `os.fork`). @@ -4609,9 +4610,10 @@ aio +$handle *isatty*+:: Returns 1 if the stream is a tty device. -+$handle *lock*+:: ++$handle *lock ?-wait?*+:: Apply a POSIX lock to the open file associated with the handle using - fcntl(2). + 'fcntl(F_SETLK)', or 'fcntl(F_SETLKW)' to wait for the lock to be available if +'-wait'+ + is specified. The handle must be open for write access. Returns 1 if the lock was successfully obtained, 0 otherwise. An error occurs if the handle is not suitable for locking (e.g. @@ -4641,7 +4643,7 @@ aio Seeks in the stream (default 'current') +$handle *sendto* 'str ?address'+:: - Sends the string, +'str'+, to the given address (host:port or path) via the socket using sendto(2). + Sends the string, +'str'+, to the given address (host:port or path) via the socket using 'sendto(2)'. This is intended for udp/dgram sockets and may give an error or behave in unintended ways for other handle types. Returns the number of bytes written. @@ -4657,8 +4659,8 @@ aio integer socket options: +sndbuf, rcvbuf+ +$handle *sync*+:: - Flush the stream, then fsync(2) to commit any changes to storage. - Only available on platforms that support fsync(2). + Flush the stream, then 'fsync(2)' to commit any changes to storage. + Only available on platforms that support 'fsync(2)'. +$handle *tell*+:: Returns the current seek position @@ -4668,7 +4670,7 @@ aio If arguments are given, they must either be a dictionary, or +setting value \...+ Abbrevations are supported for both settings and values, so the following is acceptable: +$f tty parity e input c out raw+. - Only available on platforms that support termios(3). Supported settings are: + Only available on platforms that support 'termios(3)'. Supported settings are: +*baud* 'rate'+;; Baud rate. e.g. 115200 @@ -4698,7 +4700,7 @@ aio +*vtime* 'time'+;; Timeout for noncanonical read (units of 0.1 seconds) -+$handle *ssl* *?-server cert priv?*+:: ++$handle *ssl* ?*-server* 'cert priv'?+:: Upgrades the stream to a SSL/TLS session and returns the handle. +$handle *unlock*+:: diff --git a/tests/lock.test b/tests/lock.test index 3672d6a..e7b0b2d 100644 --- a/tests/lock.test +++ b/tests/lock.test @@ -42,6 +42,19 @@ test lock-1.5 {grab lock from sub-process} { set stat } 0 +test lock-1.6 {wait for lock} { + # Run a child process that grabs the lock for 0.5 seconds + set pid [exec [info nameofexecutable] -e {set fh [open locktest.file r+]; $fh lock; sleep 0.5} >/dev/null &] + # And wait to acquire the lock in the parent. Should take ~500ms + set start [clock millis] + sleep 0.1 + $fh lock -wait + set delta [expr {[clock millis] - $start}] + if {$delta < 100} { + error "Lock acquired after ${delta}ms" + } +} {} + $fh close file delete locktest.file |