8 volatile int ready, done;
11static void* set_append(
void* argument) {
13 __atomic_store_n(&change->ready, 1, __ATOMIC_RELEASE);
14 if (!tf_wait(&change->transfer->gate, 5000))
15 change->result = fcntl(change->transfer->output, F_SETFL, O_APPEND);
16 __atomic_store_n(&change->done, 1, __ATOMIC_RELEASE);
19static int explicit_output_flags(
void) {
20 int failed = 0, copy_started = 0, flags_started = 0;
21 struct tf_file input = {.fd = -1}, output = {.fd = -1};
22 off_t from = 3, to = 24;
23 struct tf_transfer transfer = {.kind = TF_COPY_RANGE,
24 .input_offset = &from,
28 struct flag_change change = {.transfer = &transfer, .result = -2};
29 pthread_t copy, flags;
30 CHECK(!tf_create(&input,
"/tmp", 128, 19) && !tf_create(&output,
"/tmp", 128, 83));
31 CHECK(lseek(output.fd, 17, SEEK_SET) == 17);
32 transfer.input = input.fd;
33 transfer.output = output.fd;
34 CHECK(!pthread_create(©, NULL, tf_worker, &transfer));
36 CHECK(!pthread_create(&flags, NULL, set_append, &change));
38 CHECK(!tf_wait(&transfer.ready, 5000) && !tf_wait(&change.ready, 5000));
39 __atomic_store_n(&transfer.gate, 1, __ATOMIC_RELEASE);
40 CHECK(!tf_wait(&transfer.done, 5000) && !tf_wait(&change.done, 5000));
41 CHECK(change.result == 0 && (fcntl(output.fd, F_GETFL) & O_APPEND));
42 if (transfer.result == 32) {
43 CHECK(from == 35 && to == 56 && !tf_verify(output.fd, 24, 32, 3, 19));
45 CHECK(transfer.result == -1 && transfer.error == EBADF && from == 3 && to == 24);
46 CHECK(!tf_verify(output.fd, 0, 128, 0, 83));
48 CHECK(lseek(input.fd, 0, SEEK_CUR) == 0 && lseek(output.fd, 0, SEEK_CUR) == 17);
49 CHECK(copy_file_range(input.fd, &from, output.fd, &to, 1, 0) == -1 && errno == EBADF);
52 tf_diagnostic(&transfer);
53 __atomic_store_n(&transfer.gate, 1, __ATOMIC_RELEASE);
55 tf_join(copy, &transfer);
57 if (tf_wait(&change.done, 5000))
59 pthread_join(flags, NULL);
66static int reversed_pair(
int kind) {
67 int failed = 0, started = 0;
68 const size_t length = TF_CHUNK + 17;
69 struct tf_file left = {.fd = -1}, right = {.fd = -1};
70 struct tf_transfer transfers[2] = {{.kind = kind, .result = -2}, {.kind = kind, .result = -2}};
72 CHECK(!tf_create(&left,
"/tmp", 3 * length, 23) && !tf_create(&right,
"/tmp", 3 * length, 67));
73 transfers[0].input = left.fd;
74 transfers[0].output = right.fd;
75 transfers[1].input = right.fd;
76 transfers[1].output = left.fd;
77 for (
int n = 0; n < 2; ++n) {
78 transfers[n].count = length;
79 CHECK(!pthread_create(&workers[n], NULL, tf_worker, &transfers[n]));
82 CHECK(!tf_wait(&transfers[0].ready, 5000) && !tf_wait(&transfers[1].ready, 5000));
83 __atomic_store_n(&transfers[0].gate, 1, __ATOMIC_RELEASE);
84 __atomic_store_n(&transfers[1].gate, 1, __ATOMIC_RELEASE);
85 CHECK(!tf_wait(&transfers[0].done, 5000) && !tf_wait(&transfers[1].done, 5000));
86 CHECK(transfers[0].result == (ssize_t)length && transfers[1].result == (ssize_t)length);
87 CHECK(lseek(left.fd, 0, SEEK_CUR) == (off_t)(2 * length) &&
88 lseek(right.fd, 0, SEEK_CUR) == (off_t)(2 * length));
90 CHECK(pread(left.fd, &first, 1, 0) == 1);
91 const int first_seed = first == tf_pattern(0, 23) ? 23 : 67;
92 CHECK(!tf_verify(left.fd, 0, length, 0, first_seed));
93 CHECK(!tf_verify(right.fd, 0, length, 0, first_seed));
94 const int second_seed = first_seed == 23 ? 67 : 23;
95 CHECK(!tf_verify(left.fd, length, length, length, second_seed));
96 CHECK(!tf_verify(right.fd, length, length, length, second_seed));
97 CHECK(!tf_verify(left.fd, 2 * length, length, 2 * length, 23));
98 CHECK(!tf_verify(right.fd, 2 * length, length, 2 * length, 67));
101 tf_diagnostic(&transfers[0]);
102 tf_diagnostic(&transfers[1]);
104 for (
int n = 0; n < started; ++n)
105 __atomic_store_n(&transfers[n].gate, 1, __ATOMIC_RELEASE);
106 for (
int n = 0; n < started; ++n)
107 tf_join(workers[n], &transfers[n]);
112int transfer_races(
void) {
113 for (
int n = 0; n < 4; ++n)
114 if (reversed_pair(TF_SENDFILE) || reversed_pair(TF_COPY_RANGE) || explicit_output_flags())