Skip to content

Commit 2c52f47

Browse files
committed
Explicitly shutdown FIFO thread
Test "setup_fifo + (already exists)" would sometimes error with ENOENT for /tmp/test-fifo. This was because a previous test was also spawning a FIFO thread, with cleanup code that would delete said file. We had a race condition. Previously, the FIFO thread was detached, preventing manual management of threads. This commit keeps the thread attached and enforces that we manually manage the FIFO thread resource, giving us tighter control of the lifecycle.
1 parent 364e5e6 commit 2c52f47

File tree

3 files changed

+37
-33
lines changed

3 files changed

+37
-33
lines changed

src/fifo.pl

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,18 @@
22

33
:- module(fifo, []).
44

5-
%! setup_fifo() is det
5+
%! setup_fifo(Tid) is det
66
%
77
% If config:fifo_enabled/1 and config:fifo_path/1 are set, attempts to create
88
% a named pipe with mkfifo(1).
9-
% If the fifo is created, its path is passed to fifo:process_fifo/1 on a detached thread.
10-
setup_fifo() :-
9+
% If the fifo is created, its path is passed to fifo:process_fifo/1.
10+
setup_fifo(Tid) :-
1111
optcnf_then(fifo_enabled(true), optcnf_then(fifo_path(FifoPath), (
1212
catch(delete_file(FifoPath), _, true), % cleanup from previous execution
1313
string_concat("mkfifo ", FifoPath, MkFifoCmd), % no swipl predicate for this
1414
shell(MkFifoCmd, ExitCode),
1515
(ExitCode == 0 ->
16-
thread_create(fifo:process_fifo(FifoPath), _, [detached(true)])
16+
thread_create(fifo:process_fifo(FifoPath), Tid)
1717
; writeln(user_error, "Could not spawn command fifo!"))
1818
)))
1919
.
@@ -30,12 +30,18 @@
3030
%
3131
% @arg FifoPath file path to the command fifo
3232
process_fifo(FifoPath) :-
33-
open(FifoPath, read, Fifo),
34-
(read_terms(Fifo, Jobs) ->
35-
jobs_notify(Jobs)
36-
; true),
37-
close(Fifo),
38-
process_fifo(FifoPath)
33+
thread_peek_message(shutdown) ->
34+
thread_get_message(shutdown)
35+
;
36+
catch(
37+
(call_with_time_limit(0.1, open(FifoPath, read, Fifo)),
38+
(read_terms(Fifo, Jobs) ->
39+
jobs_notify(Jobs)
40+
; true),
41+
close(Fifo)
42+
), _, true
43+
),
44+
process_fifo(FifoPath)
3945
.
4046

4147
%! read_terms(++S:stream, --Terms:[term]) is semidet

src/plwm.pl

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2341,11 +2341,13 @@
23412341
update_free_win_space,
23422342
update_ws_atoms,
23432343

2344-
fifo:setup_fifo,
2344+
fifo:setup_fifo(FifoThread),
23452345

23462346
setup_hooks,
23472347
run_hook(start),
23482348

2349-
eventloop
2349+
eventloop,
2350+
thread_send_message(FifoThread, shutdown),
2351+
thread_join(FifoThread)
23502352
.
23512353

tests/unit_tests/fifo.plt

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,39 +9,35 @@ optcnf_then(fifo_path(FifoPath), Then) :- FifoPath = "/tmp/test-fifo", Then.
99
:- use_module("../../src/fifo").
1010

1111
test("setup_fifo +", [
12-
setup(
13-
optcnf_then(fifo_path(FifoPath), true)
14-
),
15-
cleanup(
12+
setup((
13+
optcnf_then(fifo_path(FifoPath), true),
14+
fifo:setup_fifo(FifoThread)
15+
)),
16+
cleanup((
17+
thread_send_message(FifoThread, shutdown),
18+
thread_join(FifoThread),
1619
delete_file(FifoPath)
17-
% Note: thread spawned by setup_fifo is detached, so no need to join
18-
)
20+
))
1921
]) :-
20-
assertion(fifo:setup_fifo),
2122
assertion(access_file(FifoPath, read)),
22-
23-
% Check if setup_fifo started the thread for process_fifo,
24-
% i.e. an extra thread is running next to 'main' and 'gc'
25-
findall(T, thread_property(T, _), Threads),
26-
assertion(list_to_set(Threads, [main, gc, _]))
23+
assertion(thread_property(FifoThread, status(running)))
2724
.
2825

2926
test("setup_fifo + (already exists)", [
3027
setup((
3128
optcnf_then(fifo_path(FifoPath), true),
32-
open(FifoPath, write, _) % create empty file
29+
open(FifoPath, write, Stream), % create empty file
30+
fifo:setup_fifo(FifoThread)
3331
)),
34-
cleanup(
32+
cleanup((
33+
close(Stream),
34+
thread_send_message(FifoThread, shutdown),
35+
thread_join(FifoThread),
3536
delete_file(FifoPath)
36-
)
37+
))
3738
]) :-
38-
assertion(fifo:setup_fifo),
3939
assertion(access_file(FifoPath, read)),
40-
41-
findall(T, thread_property(T, _), Threads),
42-
assertion(list_to_set(Threads, [main, gc, _, _]))
43-
% Note: one more thread due to execution of prior testcase,
44-
% unfortunately we cannot destroy detached threads:/
40+
assertion(thread_property(FifoThread, status(running)))
4541
.
4642

4743
test("process_fifo", [

0 commit comments

Comments
 (0)