17

flock() is PHP's portable advisory file locking function. They explicitly promote that it even works under windows:

flock() allows you to perform a simple reader/writer model which can be used on virtually every platform (including most Unix derivatives and even Windows).

I'd like to put an also portable timeout on a blocking flock() (and no busy waiting work around with the LOCK_NB option). In UNIX this can simply be achieved with setting an alarm which would send a SIGALRM:

pcntl_signal(SIGALRM, function() {});
pcntl_alarm(3);
try {
    if (!flock($handle, LOCK_EX)) {
        throw new \Exception("Timeout");
    }
} finally {
    pcntl_alarm(0);
    pcntl_signal_dispatch();
    pcntl_signal(SIGALRM, SIG_DFL);
}

Is there a portable way to put a timeout on a blocking flock()? If so, how?

Deep Kakkar
  • 5,831
  • 4
  • 39
  • 75
Markus Malkusch
  • 7,738
  • 2
  • 38
  • 67
  • 2
    `LOCK_NB` + a loop + `usleep`? – zerkms Nov 20 '16 at 23:14
  • 2
    > and no busy waiting work around with the LOCK_NB option – Markus Malkusch Nov 20 '16 at 23:14
  • http://php.net/flock – zerkms Nov 20 '16 at 23:15
  • @zerkms I'm sure he already looked there … The actual answer is that there is no way to do that portably in PHP. Windows has an alarm functionality, but it's not exposed via any extension in PHP. – bwoebi Nov 20 '16 at 23:19
  • @bwoebi well, they decided play pedantic. So did I - everything `flock` can do is explained on that page (or in php sources). PS: it is weird one even want to terminate the process instead of handling it gracefully (even with a busy waiting loop) – zerkms Nov 20 '16 at 23:19
  • @MarkusMalkusch Anyway, you'll have to mess around with a separate process in order to have it deliver an interrupting signal to your program after timeout passed. There's no other way… – bwoebi Nov 20 '16 at 23:24
  • @MarkusMalkusch "Where do you read on that page how to put a timeout under UNIX" --- it's literally sending a signal. Unblocking is just a side effect. If you're fine killing the current process - then simply `exec` a command that would kill the current PID after a timeout. – zerkms Nov 20 '16 at 23:24
  • It is not "within the same process", it is scheduled as a kernel timer. – zerkms Nov 20 '16 at 23:26
  • The comments are getting far to chatty and drifting away from the actual question. But I'd like to add that you don't have to terminate the process in UNIX. `flock()` will indicate its failure with the return value. And to prevent termination one could install a noop signal handler for `SIGALRM`. No `exec()` or other process is needed for this. And if there's no portable option, then I will simply accept the first "No, there's no portable timeout" answer. – Markus Malkusch Nov 20 '16 at 23:49

1 Answers1

3

I don't think that there is any way to do this on Windows without a busy wait / polling loop.

PHP implements flock on windows using LockFileEx (see flock_compat.c:132). As you can see from these similar questions, there is no way to set a timeout on LockFileEx or to cancel a process waiting for a LockFileEx request (i.e. there is no equivalent to the SIGALRM signal for this use-case):

  1. LockFile with timeout? (asked 2011)

Q) If I want to wait for file-lock with timeout, how would I go about it?

...

A) write a small loop to check the return code

  1. "LockFileEx can't time out it just hangs" from microsoft.public.win32.programmer.kernel mailing list, 1997

Q) Does anyone know of a way to get LockFileEx to time out ?

...

A) you can only have it fail imemdiately, sleep, and loop back until you reach some retry limit.

Community
  • 1
  • 1
Rich
  • 15,048
  • 2
  • 66
  • 119