Skip to content

Commit 0655f0d

Browse files
committed
Fix race condition
1 parent fb0e75b commit 0655f0d

File tree

1 file changed

+102
-25
lines changed

1 file changed

+102
-25
lines changed

test/stubs/stub

Lines changed: 102 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -15,25 +15,96 @@ _STUB_RESULT="${PROGRAM}_STUB_RESULT"
1515
_STUB_END="${PROGRAM}_STUB_END"
1616
_STUB_LOG="${PROGRAM}_STUB_LOG"
1717

18+
19+
STUB_LOCKFILE="${TMPDIR}/${program}-stub.lock"
20+
21+
release_lock() {
22+
rm -f "$STUB_LOCKFILE"
23+
trap - EXIT
24+
}
25+
26+
acquire_lock() {
27+
local start=$SECONDS
28+
local acquire_timeout=60
29+
local acquired=
30+
while (( SECONDS <= start + $acquire_timeout )); do
31+
32+
set -o noclobber
33+
echo -n > "$STUB_LOCKFILE" 2>/dev/null && acquired=1
34+
set +o noclobber
35+
36+
if [[ -n $acquired ]]; then
37+
trap release_lock EXIT
38+
break
39+
else
40+
# POSIX sleep(1) doesn't provide subsecond precision, but many others do
41+
sleep 0.1 2>/dev/null || sleep 1
42+
fi
43+
done
44+
if [[ -z $acquired ]]; then
45+
echo "$0: error: could not acquire stub lock in ${acquire_timeout} seconds" >&2
46+
exit 2
47+
done
48+
)
49+
50+
acquire_lock
51+
1852
[ -n "${!_STUB_LOG}" ] || eval "${_STUB_LOG}"="${TMPDIR}/${program}-stub-log"
53+
1954
if test -z "${!_STUB_END}"; then echo "$program" "$@" >>"${!_STUB_LOG}"; fi
2055

2156
[ -e "${!_STUB_PLAN}" ] || exit 1
2257
[ -n "${!_STUB_RUN}" ] || eval "${_STUB_RUN}"="${TMPDIR}/${program}-stub-run"
2358

2459

2560
# Initialize or load the stub run information.
61+
read_runfile() {
62+
if test -e "${!_STUB_RUN}"; then source "${!_STUB_RUN}"; fi
63+
}
64+
write_runfile() {
65+
{
66+
echo "${_STUB_INDEX}=${!_STUB_INDEX}"
67+
echo "${_STUB_RESULT}=${!_STUB_RESULT}"
68+
} > "${!_STUB_RUN}"
69+
}
70+
update_runfile_index() {
71+
( eval "${_STUB_INDEX}=$((${!_STUB_INDEX} + 1))"
72+
write_runfile
73+
)
74+
}
75+
update_runfile_result() {
76+
(
77+
old_result="${!_STUB_RESULT}"
78+
read_runfile
79+
new_result = $(( $old_result | ${!_STUB_RESULT} ))
80+
eval "${_STUB_RESULT}=\$new_result"
81+
write_runfile
82+
)
83+
}
84+
2685
eval "${_STUB_INDEX}"=1
2786
eval "${_STUB_RESULT}"=0
28-
if test -e "${!_STUB_RUN}"; then source "${!_STUB_RUN}"; fi
29-
30-
31-
# Loop over each line in the plan.
32-
index=0
33-
while IFS= read -r line; do
34-
index=$(($index + 1))
35-
36-
if [ -z "${!_STUB_END}" ] && [ $index -eq "${!_STUB_INDEX}" ]; then
87+
read_runfile
88+
89+
# !_STUB_END is set externally to trigger verification mode for `unstub'
90+
# Execution mode
91+
if [ -z "${!_STUB_END}" ]; then
92+
93+
update_runfile_index
94+
# Release the lock while the payload is run to allow another `stub'
95+
# of the same program to run concurrently (e.g. in a pipeline).
96+
# The plan file is supposed to be finalized before stubs are run
97+
# so no need to hold the lock while reading it.
98+
release_lock
99+
100+
# Loop over each line in the plan.
101+
index=0
102+
while IFS= read -r line; do
103+
index=$(($index + 1))
104+
if [ $index -ne "${!_STUB_INDEX}" ]; then
105+
continue;
106+
fi
107+
37108
# We found the plan line we're interested in.
38109
# Start off by assuming success.
39110
result=0
@@ -76,14 +147,34 @@ while IFS= read -r line; do
76147
else
77148
eval "${_STUB_RESULT}"=1
78149
fi
150+
151+
break
152+
done < "${!_STUB_PLAN}"
153+
154+
# If the requested index is larger than the number
155+
# of lines in the plan file, we failed.
156+
if [ "${!_STUB_INDEX}" -gt $index ]; then
157+
eval "${_STUB_RESULT}"=1
79158
fi
80-
done < "${!_STUB_PLAN}"
81159

160+
# Write out the run information.
161+
acquire_lock
162+
update_runfile_result
163+
release_lock
164+
165+
exit "$status"
82166

167+
fi
168+
169+
# Verification mode (`unstub')
83170
if [ -n "${!_STUB_END}" ]; then
171+
172+
# `unstub' is supposed to run after any stubs are finished
173+
release_lock
174+
84175
# If the number of lines in the plan is larger than
85176
# the requested index, we failed.
86-
if [ $index -ge "${!_STUB_INDEX}" ]; then
177+
if [ "$(wc -l "${!_STUB_PLAN}")" -ge "${!_STUB_INDEX}" ]; then
87178
eval "${_STUB_RESULT}"=1
88179
fi
89180
if [ "${!_STUB_RESULT}" -ne 0 ]; then
@@ -102,18 +193,4 @@ if [ -n "${!_STUB_END}" ]; then
102193
# Return the result.
103194
exit "${!_STUB_RESULT}"
104195

105-
else
106-
# If the requested index is larger than the number
107-
# of lines in the plan file, we failed.
108-
if [ "${!_STUB_INDEX}" -gt $index ]; then
109-
eval "${_STUB_RESULT}"=1
110-
fi
111-
112-
# Write out the run information.
113-
{ echo "${_STUB_INDEX}=$((${!_STUB_INDEX} + 1))"
114-
echo "${_STUB_RESULT}=${!_STUB_RESULT}"
115-
} > "${!_STUB_RUN}"
116-
117-
exit "$status"
118-
119196
fi

0 commit comments

Comments
 (0)