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
|