Timing out a syscall to flock?

709 views
Skip to first unread message

Nate Finch

unread,
May 14, 2016, 6:59:57 PM5/14/16
to golang-nuts
Anyone have some magic to allow me to time out a syscall to flock on Linux? Google says you can signal the process with sigalrm but more Google says that the signal has to go to exactly the same thread as the blocking flock, which of course is tough with goroutines (and in testing, signalling my own process from another goroutines didn't work). Any other suggestions? I currently am using a nonblocking call to flock and just looping with a sleep, but that feels really janky.

James Aguilar

unread,
May 14, 2016, 10:23:41 PM5/14/16
to golang-nuts
On Saturday, May 14, 2016 at 3:59:57 PM UTC-7, Nate Finch wrote:
Anyone have some magic to allow me to time out a syscall to flock on Linux?  Google says you can signal the process with sigalrm but more Google says that the signal has to go to exactly the same thread as the blocking flock, which of course is tough with goroutines (and in testing, signalling my own process from another goroutines didn't work). Any other suggestions?  I currently am using a nonblocking call to flock and just looping with a sleep, but that feels really janky.

Could you do something like:

2. Gettid
3. Write down said tid where the entity wishing to stop the lock can find it.
4. flock

? Then you can signal the correct thread per the information written down in step 3.

Ian Lance Taylor

unread,
May 15, 2016, 12:15:59 AM5/15/16
to Nate Finch, golang-nuts
On Sat, May 14, 2016 at 3:59 PM, Nate Finch <nate....@gmail.com> wrote:
> Anyone have some magic to allow me to time out a syscall to flock on Linux? Google says you can signal the process with sigalrm but more Google says that the signal has to go to exactly the same thread as the blocking flock, which of course is tough with goroutines (and in testing, signalling my own process from another goroutines didn't work). Any other suggestions? I currently am using a nonblocking call to flock and just looping with a sleep, but that feels really janky.

What is your overall goal? Would it work to simply write something like

c := make(chan error)
go func() {
c <- syscall.Flock(...)
}()
select {
case err := <-c:
// Check err to see if lock was acquired successfully.
case <-time.After(time.Hour):
go func() {
err := <-c
if err == nil {
syscall.Flock(fd, syscall.LOCK_UN)
}
}()
// Lock timed out.
}

Nate Finch

unread,
May 16, 2016, 12:57:53 PM5/16/16
to golang-nuts
The point is that we have a guarantee about one process executing at a time. We're using a crummy bespoke hack that ostensibly works like flock, but less reliably. We'd like to switch to using flock. However, we need to be able to time out in case a misbehaving process hangs or otherwise takes way too long while running with the lock.

Having a single goroutine that may block for an extended period is probably ok, I was just hoping to avoid it, if someone had some way of signalling the syscall to terminate it.

FWIW, closing the file descriptor and/or unlocking from another goroutine did not unblock the goroutine waiting on the flock syscall (I had hoped it would, but my tests say no).

Konstantin Khomoutov

unread,
May 16, 2016, 1:40:01 PM5/16/16
to Nate Finch, golang-nuts
You could try to look at using a so-called "abstract" Unix-domain
socket to synchronize between your processes. These sockets do not
create filesystem objects and are hence relatively easy to manage.

The active process could bind() to it, and another process could do
just the same -- with its attempt failing.

You could also try to use POSIX process-shared semaphores but Go does
not have stock syscall wrappers for them yet (and I'd say it appears to
be more clumsy than a plain socket to me). But see [1].

1. https://groups.google.com/d/msg/golang-nuts/zpwbWye5o7o/8f_UzLXxBQAJ

Ian Lance Taylor

unread,
May 16, 2016, 2:26:20 PM5/16/16
to Nate Finch, golang-nuts
On Mon, May 16, 2016 at 9:57 AM, Nate Finch <nate....@gmail.com> wrote:
> The point is that we have a guarantee about one process executing at a time. We're using a crummy bespoke hack that ostensibly works like flock, but less reliably. We'd like to switch to using flock. However, we need to be able to time out in case a misbehaving process hangs or otherwise takes way too long while running with the lock.
>
> Having a single goroutine that may block for an extended period is probably ok, I was just hoping to avoid it, if someone had some way of signalling the syscall to terminate it.

Using a signal won't work. The Go runtime installs all signals with
the SA_RESTART flag set, and at least on GNU/Linux that means that the
flock system call does not return even if the thread on which it is
running receives a signal.

There are various ways to ensure that only one process executes at a
time. However, offhand I can't think of any that support timeouts,
avoid race conditions, and don't use signals. I would go with the
dangling goroutine.

Ian

Nate Finch

unread,
May 16, 2016, 3:10:01 PM5/16/16
to golang-nuts, nate....@gmail.com
Thanks for the advice, Ian.

Lars Tørnes Hansen

unread,
May 17, 2016, 6:51:34 AM5/17/16
to golang-nuts
Processor affinity / cpu pinning could solve your "the point is that we have a guarantee about one process executing at a time.".

Nate Finch

unread,
May 17, 2016, 10:07:48 AM5/17/16
to golang-nuts
Ahh, thanks for the suggestion, but no.  We would likely have a lot of bad side effects, and a little too hacky for my taste.
Reply all
Reply to author
Forward
0 new messages