File: flock

package info (click to toggle)
util-linux 2.41.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 92,844 kB
  • sloc: ansic: 179,146; sh: 22,716; yacc: 1,284; makefile: 525; xml: 422; python: 316; lex: 89; ruby: 75; csh: 37; exp: 19; sed: 16; perl: 15; sql: 9
file content (143 lines) | stat: -rwxr-xr-x 3,875 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#!/bin/bash

# This file is part of util-linux.
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This file is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

TS_TOPDIR="${0%/*}/../.."
TS_DESC="flock"

. "$TS_TOPDIR"/functions.sh
ts_init "$*"

ts_check_test_command "$TS_CMD_FLOCK"
ts_check_prog "pgrep"
ts_check_prog "timeout"


function do_lock {
	local opts="$1"
	local expected_rc="$2"
	local mesg="$3"

	$TS_CMD_FLOCK $1 $TS_OUTDIR/lockfile \
		echo "$mesg" \
		>> $TS_OUTPUT 2>> $TS_ERRLOG

	local rc="$?"

	if [  "$rc" == "$expected_rc" ]; then
		ts_log "Success"
	else
		ts_log "Failed [rc=$rc]"
	fi
}

for api in flock fcntl ; do
	case $api in
		(flock)
			subtest_prefix=""
			api_arg="" ;;
		(fcntl)
			subtest_prefix="fcntl-"
			api_arg="--fcntl" ;;
	esac

	# general lock
	GEN_OUTPUT="$TS_OUTPUT"
	START=$(date '+%s')
	# running flock in background is not the best usage example
	$TS_CMD_FLOCK $api_arg --shared $TS_OUTDIR/lockfile \
		      bash -c "echo 'API: $api(2)'; echo 'Locking'; sleep 3; echo 'Unlocking'" \
		      >> $GEN_OUTPUT 2>&1 &
	pid=$!

	# check for running background process
	if [ "$pid" -le "0" ] || ! kill -s 0 "$pid" &>/dev/null; then
		ts_die "unable to run flock"
	fi
	# the lock should be established when flock has a child
	timeout 1s bash -c "while ! pgrep -P $pid >/dev/null; do sleep 0.1 ;done" \
		|| ts_die "timeout waiting for flock child"

	ts_init_subtest "${subtest_prefix}non-block"
	do_lock "${api_arg} --nonblock --conflict-exit-code 123" 123 "You will never see this!"
	ts_finalize_subtest


	ts_init_subtest "${subtest_prefix}no-fork"
	do_lock "${api_arg} --no-fork --nonblock --conflict-exit-code 123" 123 "You will never see this!"
	ts_finalize_subtest


	ts_init_subtest "${subtest_prefix}shared"
	do_lock "${api_arg} --shared" 0 "Have shared lock"
	ts_finalize_subtest


	# this is the same as non-block test (exclusive lock is the default), but here
	# we explicitly specify --exclusive on command line
	ts_init_subtest "${subtest_prefix}exclusive"
	do_lock "${api_arg} --nonblock --exclusive --conflict-exit-code 123" 123 "You will never see this!"
	ts_finalize_subtest


	ts_init_subtest "${subtest_prefix}fd"
	cd "$TS_OUTDIR"
	rm 4 2> /dev/null
	exec 4<>$TS_OUTDIR/lockfile || ts_log "Could not open lockfile"
	$TS_CMD_FLOCK $api_arg --nonblock --exclusive --conflict-exit-code 123 4 \
		      >> $TS_OUTPUT 2>> $TS_ERRLOG

	rc="$?"

	if [  "$rc" == "123" ]; then
		ts_log "Success"
	else
		ts_log "Failed [rc=$rc]"
	fi
	[ -f 4 ] && ts_log "fd file should not exist"
	ts_finalize_subtest

	# fcntl locks are independent of flock locks, so we should be able to get an exclusive flock lock.
	if [ "$api" = "fcntl" ] ; then
		ts_init_subtest "fcntl-vs-flock"
		do_lock "--nonblock --exclusive" 0 "flock vs fcntl"
		ts_finalize_subtest
	fi

	ts_init_subtest "${subtest_prefix}timeout"
	do_lock "${api_arg} --timeout 5 --conflict-exit-code 5" 0 "After timeout."
	END=$(date '+%s')
	ts_finalize_subtest


	# expected is 3 seconds (see "sleep 3" for the general lock), but we should not
	# rely on exact number due to scheduler, machine load, etc. Let's check for
	# inmterval <3,5>.
	#
	ts_init_subtest "${subtest_prefix}time-check"
	TIMEDIFF=$(( $END - $START ))
	if [ $TIMEDIFF -lt 3 ]; then
		ts_log "general lock failed [$TIMEDIFF sec]"
	elif [ $TIMEDIFF -gt 5 ]; then
		ts_log "wait too long [$TIMEDIFF sec]"
	else
		ts_log "success"
	fi
	ts_finalize_subtest "diff ${TIMEDIFF} sec"


	echo "Unlocked" >> $GEN_OUTPUT

done

ts_finalize