blob: 5e5b11496cbddaaa5a06a53be3416d391631b065 [file] [log] [blame]
Cyril Hrubisab8388c2012-11-28 15:42:17 +01001/*
Cyril Hrubis9f136a42015-02-17 17:16:09 +01002 * Copyright (C) 2015 Cyril Hrubis <chrubis@suse.cz>
Cyril Hrubisab8388c2012-11-28 15:42:17 +01003 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of version 2 of the GNU General Public License as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it would be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11 *
12 * Further, this software is distributed without any warranty that it is
13 * free of the rightful claim of any third person regarding infringement
14 * or the like. Any license provided herein, whether implied or
15 * otherwise, applies only to this software file. Patent licenses, if
16 * any, provided herein do not apply to combinations of this program with
17 * other software, or any other product whatsoever.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 */
23
Cyril Hrubis9f136a42015-02-17 17:16:09 +010024#include <stdint.h>
25#include <limits.h>
Cyril Hrubisab8388c2012-11-28 15:42:17 +010026#include <errno.h>
Cyril Hrubis9f136a42015-02-17 17:16:09 +010027#include <sys/syscall.h>
28#include <linux/futex.h>
Cyril Hrubisab8388c2012-11-28 15:42:17 +010029
Cyril Hrubis9f136a42015-02-17 17:16:09 +010030#include "test.h"
31#include "safe_macros.h"
Stanislav Kholmanskikh55712282015-05-26 12:16:16 +030032#include "lapi/futex.h"
Cyril Hrubisab8388c2012-11-28 15:42:17 +010033
Cyril Hrubis9f136a42015-02-17 17:16:09 +010034#define DEFAULT_MSEC_TIMEOUT 10000
35
Stanislav Kholmanskikh57027652015-05-26 13:21:10 +030036futex_t *tst_futexes;
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +010037unsigned int tst_max_futexes;
Cyril Hrubis9f136a42015-02-17 17:16:09 +010038
39void tst_checkpoint_init(const char *file, const int lineno,
40 void (*cleanup_fn)(void))
Stanislav Kholmanskikhcb80f402013-11-14 10:37:57 +040041{
42 int fd;
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +010043 unsigned int page_size;
Stanislav Kholmanskikhcb80f402013-11-14 10:37:57 +040044
Stanislav Kholmanskikh57027652015-05-26 13:21:10 +030045 if (tst_futexes) {
Cyril Hrubis9f136a42015-02-17 17:16:09 +010046 tst_brkm(TBROK, cleanup_fn,
Petr Vorelf1828392017-12-05 10:44:43 +010047 "%s: %d checkpoints already initialized",
Cyril Hrubis9f136a42015-02-17 17:16:09 +010048 file, lineno);
Cyril Hrubisd101cab2017-02-14 11:48:46 +010049 return;
Cyril Hrubis9f136a42015-02-17 17:16:09 +010050 }
Stanislav Kholmanskikhcb80f402013-11-14 10:37:57 +040051
Cyril Hrubis9f136a42015-02-17 17:16:09 +010052 /*
53 * The parent test process is responsible for creating the temporary
54 * directory and therefore must pass non-zero cleanup (to remove the
55 * directory if something went wrong).
56 *
57 * We cannot do this check unconditionally because if we need to init
58 * the checkpoint from a binary that was started by exec() the
59 * tst_tmpdir_created() will return false because the tmpdir was
60 * created by parent. In this case we expect the subprogram can call
61 * the init as a first function with NULL as cleanup function.
62 */
63 if (cleanup_fn && !tst_tmpdir_created()) {
64 tst_brkm(TBROK, cleanup_fn,
65 "%s:%d You have to create test temporary directory "
66 "first (call tst_tmpdir())", file, lineno);
Cyril Hrubisd101cab2017-02-14 11:48:46 +010067 return;
Cyril Hrubis9f136a42015-02-17 17:16:09 +010068 }
Stanislav Kholmanskikhcb80f402013-11-14 10:37:57 +040069
Cyril Hrubis9f136a42015-02-17 17:16:09 +010070 page_size = getpagesize();
71
72 fd = SAFE_OPEN(cleanup_fn, "checkpoint_futex_base_file",
73 O_RDWR | O_CREAT, 0666);
74
75 SAFE_FTRUNCATE(cleanup_fn, fd, page_size);
76
Stanislav Kholmanskikh57027652015-05-26 13:21:10 +030077 tst_futexes = SAFE_MMAP(cleanup_fn, NULL, page_size,
Cyril Hrubis9f136a42015-02-17 17:16:09 +010078 PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
79
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +010080 tst_max_futexes = page_size / sizeof(uint32_t);
81
Cyril Hrubis9f136a42015-02-17 17:16:09 +010082 SAFE_CLOSE(cleanup_fn, fd);
83}
84
85int tst_checkpoint_wait(unsigned int id, unsigned int msec_timeout)
86{
87 struct timespec timeout;
Cyril Hrubis07debb72019-03-18 14:42:27 +010088 int ret;
Cyril Hrubis9f136a42015-02-17 17:16:09 +010089
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +010090 if (id >= tst_max_futexes) {
Cyril Hrubis9f136a42015-02-17 17:16:09 +010091 errno = EOVERFLOW;
92 return -1;
93 }
94
95 timeout.tv_sec = msec_timeout/1000;
96 timeout.tv_nsec = (msec_timeout%1000) * 1000000;
97
Cyril Hrubis07debb72019-03-18 14:42:27 +010098 do {
99 ret = syscall(SYS_futex, &tst_futexes[id], FUTEX_WAIT,
100 tst_futexes[id], &timeout);
101 } while (ret == -1 && errno == EINTR);
102
103 return ret;
Cyril Hrubis9f136a42015-02-17 17:16:09 +0100104}
105
106int tst_checkpoint_wake(unsigned int id, unsigned int nr_wake,
107 unsigned int msec_timeout)
108{
109 unsigned int msecs = 0, waked = 0;
110
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100111 if (id >= tst_max_futexes) {
Cyril Hrubis9f136a42015-02-17 17:16:09 +0100112 errno = EOVERFLOW;
113 return -1;
114 }
115
Jan Stancek768157b2016-05-11 13:36:45 +0200116 for (;;) {
Stanislav Kholmanskikh57027652015-05-26 13:21:10 +0300117 waked += syscall(SYS_futex, &tst_futexes[id], FUTEX_WAKE,
118 INT_MAX, NULL);
Jan Stancek768157b2016-05-11 13:36:45 +0200119
120 if (waked == nr_wake)
121 break;
122
Cyril Hrubis9f136a42015-02-17 17:16:09 +0100123 usleep(1000);
124 msecs++;
125
126 if (msecs >= msec_timeout) {
127 errno = ETIMEDOUT;
Stanislav Kholmanskikhcb80f402013-11-14 10:37:57 +0400128 return -1;
129 }
Jan Stancek768157b2016-05-11 13:36:45 +0200130 }
Stanislav Kholmanskikhcb80f402013-11-14 10:37:57 +0400131
Cyril Hrubis9f136a42015-02-17 17:16:09 +0100132 return 0;
Stanislav Kholmanskikhcb80f402013-11-14 10:37:57 +0400133}
134
Cyril Hrubis9f136a42015-02-17 17:16:09 +0100135void tst_safe_checkpoint_wait(const char *file, const int lineno,
Cyril Hrubis554c2702017-02-13 14:51:23 +0100136 void (*cleanup_fn)(void), unsigned int id,
137 unsigned int msec_timeout)
Cyril Hrubisab8388c2012-11-28 15:42:17 +0100138{
Cyril Hrubis554c2702017-02-13 14:51:23 +0100139 int ret;
140
141 if (!msec_timeout)
142 msec_timeout = DEFAULT_MSEC_TIMEOUT;
143
144 ret = tst_checkpoint_wait(id, msec_timeout);
Matus Marhefka5b031502014-10-02 13:32:33 +0200145
Cyril Hrubis9f136a42015-02-17 17:16:09 +0100146 if (ret) {
Cyril Hrubisab8388c2012-11-28 15:42:17 +0100147 tst_brkm(TBROK | TERRNO, cleanup_fn,
Cyril Hrubis9f136a42015-02-17 17:16:09 +0100148 "%s:%d: tst_checkpoint_wait(%u, %i)",
Cyril Hrubis554c2702017-02-13 14:51:23 +0100149 file, lineno, id, msec_timeout);
Cyril Hrubisab8388c2012-11-28 15:42:17 +0100150 }
Cyril Hrubisab8388c2012-11-28 15:42:17 +0100151}
152
Cyril Hrubis9f136a42015-02-17 17:16:09 +0100153void tst_safe_checkpoint_wake(const char *file, const int lineno,
154 void (*cleanup_fn)(void), unsigned int id,
155 unsigned int nr_wake)
Cyril Hrubisab8388c2012-11-28 15:42:17 +0100156{
Cyril Hrubis9f136a42015-02-17 17:16:09 +0100157 int ret = tst_checkpoint_wake(id, nr_wake, DEFAULT_MSEC_TIMEOUT);
Cyril Hrubisab8388c2012-11-28 15:42:17 +0100158
Cyril Hrubis9f136a42015-02-17 17:16:09 +0100159 if (ret) {
Cyril Hrubisab8388c2012-11-28 15:42:17 +0100160 tst_brkm(TBROK | TERRNO, cleanup_fn,
Cyril Hrubis9f136a42015-02-17 17:16:09 +0100161 "%s:%d: tst_checkpoint_wake(%u, %u, %i)",
162 file, lineno, id, nr_wake, DEFAULT_MSEC_TIMEOUT);
Cyril Hrubisab8388c2012-11-28 15:42:17 +0100163 }
Cyril Hrubisab8388c2012-11-28 15:42:17 +0100164}