Skip to content

Commit 44df89c

Browse files
authored
[libc] add pthread_rwlock_clockrdlock and pthread_rwlock_clockwrlock … (#100543)
1 parent a7e8bdd commit 44df89c

File tree

13 files changed

+267
-3
lines changed

13 files changed

+267
-3
lines changed

libc/config/linux/aarch64/entrypoints.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,8 @@ if(LLVM_LIBC_FULL_BUILD)
692692
libc.src.pthread.pthread_mutexattr_setrobust
693693
libc.src.pthread.pthread_mutexattr_settype
694694
libc.src.pthread.pthread_once
695+
libc.src.pthread.pthread_rwlock_clockrdlock
696+
libc.src.pthread.pthread_rwlock_clockwrlock
695697
libc.src.pthread.pthread_rwlock_destroy
696698
libc.src.pthread.pthread_rwlock_init
697699
libc.src.pthread.pthread_rwlock_rdlock

libc/config/linux/riscv/entrypoints.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -703,6 +703,8 @@ if(LLVM_LIBC_FULL_BUILD)
703703
libc.src.pthread.pthread_mutexattr_setrobust
704704
libc.src.pthread.pthread_mutexattr_settype
705705
libc.src.pthread.pthread_once
706+
libc.src.pthread.pthread_rwlock_clockrdlock
707+
libc.src.pthread.pthread_rwlock_clockwrlock
706708
libc.src.pthread.pthread_rwlock_destroy
707709
libc.src.pthread.pthread_rwlock_init
708710
libc.src.pthread.pthread_rwlock_rdlock

libc/config/linux/x86_64/entrypoints.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -790,6 +790,8 @@ if(LLVM_LIBC_FULL_BUILD)
790790
libc.src.pthread.pthread_mutexattr_setrobust
791791
libc.src.pthread.pthread_mutexattr_settype
792792
libc.src.pthread.pthread_once
793+
libc.src.pthread.pthread_rwlock_clockrdlock
794+
libc.src.pthread.pthread_rwlock_clockwrlock
793795
libc.src.pthread.pthread_rwlock_destroy
794796
libc.src.pthread.pthread_rwlock_init
795797
libc.src.pthread.pthread_rwlock_rdlock

libc/docs/dev/undefined_behavior.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,3 +93,8 @@ direction in this case.
9393
Non-const Constant Return Values
9494
--------------------------------
9595
Some libc functions, like ``dlerror()``, return ``char *`` instead of ``const char *`` and then tell the caller they promise not to to modify this value. Any modification of this value is undefined behavior.
96+
97+
Unrecognized ``clockid_t`` values for ``pthread_rwlock_clock*`` APIs
98+
----------------------------------------------------------------------
99+
POSIX.1-2024 only demands support for ``CLOCK_REALTIME`` and ``CLOCK_MONOTONIC``. Currently,
100+
as in LLVM libc, if other clock ids are used, they will be treated as monotonic clocks.

libc/newhdrgen/yaml/pthread.yaml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,20 @@ functions:
370370
arguments:
371371
- type: pthread_rwlock_t *__restrict
372372
- type: const struct timespec *__restrict
373+
- name: pthread_rwlock_clockrdlock
374+
standards: POSIX
375+
return_type: int
376+
arguments:
377+
- type: pthread_rwlock_t *__restrict
378+
- type: clockid_t
379+
- type: const struct timespec *__restrict
380+
- name: pthread_rwlock_clockwrlock
381+
standards: POSIX
382+
return_type: int
383+
arguments:
384+
- type: pthread_rwlock_t *__restrict
385+
- type: clockid_t
386+
- type: const struct timespec *__restrict
373387
- name: pthread_rwlock_rdlock
374388
standards: POSIX
375389
return_type: int

libc/spec/posix.td

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1325,6 +1325,16 @@ def POSIX : StandardSpec<"POSIX"> {
13251325
RetValSpec<IntType>,
13261326
[ArgSpec<RestrictedPThreadRWLockTPtr>, ArgSpec<ConstRestrictStructTimeSpecPtr>]
13271327
>,
1328+
FunctionSpec<
1329+
"pthread_rwlock_clockrdlock",
1330+
RetValSpec<IntType>,
1331+
[ArgSpec<RestrictedPThreadRWLockTPtr>, ArgSpec<ClockIdT>, ArgSpec<ConstRestrictStructTimeSpecPtr>]
1332+
>,
1333+
FunctionSpec<
1334+
"pthread_rwlock_clockwrlock",
1335+
RetValSpec<IntType>,
1336+
[ArgSpec<RestrictedPThreadRWLockTPtr>, ArgSpec<ClockIdT>, ArgSpec<ConstRestrictStructTimeSpecPtr>]
1337+
>,
13281338
FunctionSpec<
13291339
"pthread_rwlock_rdlock",
13301340
RetValSpec<IntType>,

libc/src/pthread/CMakeLists.txt

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -556,6 +556,28 @@ add_entrypoint_object(
556556
libc.src.__support.threads.linux.rwlock
557557
)
558558

559+
add_entrypoint_object(
560+
pthread_rwlock_clockrdlock
561+
SRCS
562+
pthread_rwlock_clockrdlock.cpp
563+
HDRS
564+
pthread_rwlock_clockrdlock.h
565+
DEPENDS
566+
libc.include.pthread
567+
libc.src.__support.threads.linux.rwlock
568+
)
569+
570+
add_entrypoint_object(
571+
pthread_rwlock_clockwrlock
572+
SRCS
573+
pthread_rwlock_clockwrlock.cpp
574+
HDRS
575+
pthread_rwlock_clockwrlock.h
576+
DEPENDS
577+
libc.include.pthread
578+
libc.src.__support.threads.linux.rwlock
579+
)
580+
559581
add_entrypoint_object(
560582
pthread_rwlock_timedrdlock
561583
SRCS
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
//===-- Implementation of the Rwlock's clockrdlock function ---------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "src/pthread/pthread_rwlock_clockrdlock.h"
10+
11+
#include "hdr/errno_macros.h"
12+
#include "src/__support/common.h"
13+
#include "src/__support/macros/config.h"
14+
#include "src/__support/threads/linux/rwlock.h"
15+
16+
#include <pthread.h>
17+
18+
namespace LIBC_NAMESPACE_DECL {
19+
20+
static_assert(
21+
sizeof(RwLock) == sizeof(pthread_rwlock_t) &&
22+
alignof(RwLock) == alignof(pthread_rwlock_t),
23+
"The public pthread_rwlock_t type must be of the same size and alignment "
24+
"as the internal rwlock type.");
25+
26+
LLVM_LIBC_FUNCTION(int, pthread_rwlock_clockrdlock,
27+
(pthread_rwlock_t * rwlock, clockid_t clockid,
28+
const timespec *abstime)) {
29+
if (!rwlock)
30+
return EINVAL;
31+
if (clockid != CLOCK_MONOTONIC && clockid != CLOCK_REALTIME)
32+
return EINVAL;
33+
bool is_realtime = (clockid == CLOCK_REALTIME);
34+
RwLock *rw = reinterpret_cast<RwLock *>(rwlock);
35+
LIBC_ASSERT(abstime && "clockrdlock called with a null timeout");
36+
auto timeout = internal::AbsTimeout::from_timespec(
37+
*abstime, /*is_realtime=*/is_realtime);
38+
if (LIBC_LIKELY(timeout.has_value()))
39+
return static_cast<int>(rw->read_lock(timeout.value()));
40+
41+
switch (timeout.error()) {
42+
case internal::AbsTimeout::Error::Invalid:
43+
return EINVAL;
44+
case internal::AbsTimeout::Error::BeforeEpoch:
45+
return ETIMEDOUT;
46+
}
47+
__builtin_unreachable();
48+
}
49+
50+
} // namespace LIBC_NAMESPACE_DECL
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//===-- Implementation header for Rwlock's clockrdlock function --*- C++-*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLVM_LIBC_SRC_PTHREAD_PTHREAD_RWLOCK_CLOCKRDLOCK_H
10+
#define LLVM_LIBC_SRC_PTHREAD_PTHREAD_RWLOCK_CLOCKRDLOCK_H
11+
12+
#include "src/__support/macros/config.h"
13+
#include <pthread.h>
14+
15+
namespace LIBC_NAMESPACE_DECL {
16+
17+
int pthread_rwlock_clockrdlock(pthread_rwlock_t *__restrict rwlock,
18+
clockid_t clockid,
19+
const timespec *__restrict abstime);
20+
21+
} // namespace LIBC_NAMESPACE_DECL
22+
23+
#endif // LLVM_LIBC_SRC_PTHREAD_PTHREAD_RWLOCK_CLOCKRDLOCK_H
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
//===-- Implementation of the Rwlock's clockwrlock function----------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "src/pthread/pthread_rwlock_clockwrlock.h"
10+
11+
#include "hdr/errno_macros.h"
12+
#include "src/__support/common.h"
13+
#include "src/__support/macros/config.h"
14+
#include "src/__support/threads/linux/rwlock.h"
15+
#include "src/__support/time/linux/abs_timeout.h"
16+
17+
#include <pthread.h>
18+
19+
namespace LIBC_NAMESPACE_DECL {
20+
21+
static_assert(
22+
sizeof(RwLock) == sizeof(pthread_rwlock_t) &&
23+
alignof(RwLock) == alignof(pthread_rwlock_t),
24+
"The public pthread_rwlock_t type must be of the same size and alignment "
25+
"as the internal rwlock type.");
26+
27+
LLVM_LIBC_FUNCTION(int, pthread_rwlock_clockwrlock,
28+
(pthread_rwlock_t * rwlock, clockid_t clockid,
29+
const timespec *abstime)) {
30+
if (!rwlock)
31+
return EINVAL;
32+
if (clockid != CLOCK_MONOTONIC && clockid != CLOCK_REALTIME)
33+
return EINVAL;
34+
bool is_realtime = (clockid == CLOCK_REALTIME);
35+
RwLock *rw = reinterpret_cast<RwLock *>(rwlock);
36+
LIBC_ASSERT(abstime && "clockwrlock called with a null timeout");
37+
auto timeout = internal::AbsTimeout::from_timespec(
38+
*abstime, /*is_realtime=*/is_realtime);
39+
if (LIBC_LIKELY(timeout.has_value()))
40+
return static_cast<int>(rw->write_lock(timeout.value()));
41+
42+
switch (timeout.error()) {
43+
case internal::AbsTimeout::Error::Invalid:
44+
return EINVAL;
45+
case internal::AbsTimeout::Error::BeforeEpoch:
46+
return ETIMEDOUT;
47+
}
48+
__builtin_unreachable();
49+
}
50+
51+
} // namespace LIBC_NAMESPACE_DECL
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//===-- Implementation header for Rwlock's clockwrlock function --*- C++-*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLVM_LIBC_SRC_PTHREAD_PTHREAD_RWLOCK_CLOCKWRLOCK_H
10+
#define LLVM_LIBC_SRC_PTHREAD_PTHREAD_RWLOCK_CLOCKWRLOCK_H
11+
12+
#include "src/__support/macros/config.h"
13+
#include <pthread.h>
14+
15+
namespace LIBC_NAMESPACE_DECL {
16+
17+
int pthread_rwlock_clockwrlock(pthread_rwlock_t *__restrict rwlock,
18+
clockid_t clockid,
19+
const timespec *__restrict abstime);
20+
21+
} // namespace LIBC_NAMESPACE_DECL
22+
23+
#endif // LLVM_LIBC_SRC_PTHREAD_PTHREAD_RWLOCK_CLOCKWRLOCK_H

libc/test/integration/src/pthread/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,11 @@ add_integration_test(
3232
libc.src.pthread.pthread_rwlock_rdlock
3333
libc.src.pthread.pthread_rwlock_tryrdlock
3434
libc.src.pthread.pthread_rwlock_timedrdlock
35+
libc.src.pthread.pthread_rwlock_clockrdlock
3536
libc.src.pthread.pthread_rwlock_wrlock
3637
libc.src.pthread.pthread_rwlock_trywrlock
3738
libc.src.pthread.pthread_rwlock_timedwrlock
39+
libc.src.pthread.pthread_rwlock_clockwrlock
3840
libc.src.pthread.pthread_rwlock_unlock
3941
libc.src.pthread.pthread_create
4042
libc.src.pthread.pthread_join

libc/test/integration/src/pthread/pthread_rwlock_test.cpp

Lines changed: 61 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
#include "src/__support/threads/sleep.h"
1616
#include "src/pthread/pthread_create.h"
1717
#include "src/pthread/pthread_join.h"
18+
#include "src/pthread/pthread_rwlock_clockrdlock.h"
19+
#include "src/pthread/pthread_rwlock_clockwrlock.h"
1820
#include "src/pthread/pthread_rwlock_destroy.h"
1921
#include "src/pthread/pthread_rwlock_init.h"
2022
#include "src/pthread/pthread_rwlock_rdlock.h"
@@ -112,6 +114,12 @@ static void nullptr_test() {
112114
ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_wrlock(nullptr), EINVAL);
113115
ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_timedrdlock(nullptr, &ts), EINVAL);
114116
ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_timedwrlock(nullptr, &ts), EINVAL);
117+
ASSERT_EQ(
118+
LIBC_NAMESPACE::pthread_rwlock_clockrdlock(nullptr, CLOCK_MONOTONIC, &ts),
119+
EINVAL);
120+
ASSERT_EQ(
121+
LIBC_NAMESPACE::pthread_rwlock_clockwrlock(nullptr, CLOCK_MONOTONIC, &ts),
122+
EINVAL);
115123
ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_tryrdlock(nullptr), EINVAL);
116124
ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_trywrlock(nullptr), EINVAL);
117125
ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_unlock(nullptr), EINVAL);
@@ -159,16 +167,40 @@ static void unusual_timespec_test() {
159167
timespec ts = {0, -1};
160168
ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_timedrdlock(&rwlock, &ts), EINVAL);
161169
ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_timedwrlock(&rwlock, &ts), EINVAL);
170+
ASSERT_EQ(
171+
LIBC_NAMESPACE::pthread_rwlock_clockrdlock(&rwlock, CLOCK_MONOTONIC, &ts),
172+
EINVAL);
173+
ASSERT_EQ(
174+
LIBC_NAMESPACE::pthread_rwlock_clockwrlock(&rwlock, CLOCK_MONOTONIC, &ts),
175+
EINVAL);
162176
ts.tv_nsec = 1'000'000'000;
163177
ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_timedrdlock(&rwlock, &ts), EINVAL);
178+
ASSERT_EQ(
179+
LIBC_NAMESPACE::pthread_rwlock_clockrdlock(&rwlock, CLOCK_MONOTONIC, &ts),
180+
EINVAL);
181+
ASSERT_EQ(
182+
LIBC_NAMESPACE::pthread_rwlock_clockwrlock(&rwlock, CLOCK_MONOTONIC, &ts),
183+
EINVAL);
164184
ts.tv_nsec += 1;
165185
ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_timedwrlock(&rwlock, &ts), EINVAL);
186+
ASSERT_EQ(
187+
LIBC_NAMESPACE::pthread_rwlock_clockrdlock(&rwlock, CLOCK_MONOTONIC, &ts),
188+
EINVAL);
189+
ASSERT_EQ(
190+
LIBC_NAMESPACE::pthread_rwlock_clockwrlock(&rwlock, CLOCK_MONOTONIC, &ts),
191+
EINVAL);
166192
ts.tv_nsec = 0;
167193
ts.tv_sec = -1;
168194
ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_timedrdlock(&rwlock, &ts),
169195
ETIMEDOUT);
170196
ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_timedwrlock(&rwlock, &ts),
171197
ETIMEDOUT);
198+
ASSERT_EQ(
199+
LIBC_NAMESPACE::pthread_rwlock_clockrdlock(&rwlock, CLOCK_MONOTONIC, &ts),
200+
ETIMEDOUT);
201+
ASSERT_EQ(
202+
LIBC_NAMESPACE::pthread_rwlock_clockwrlock(&rwlock, CLOCK_MONOTONIC, &ts),
203+
ETIMEDOUT);
172204
}
173205

174206
static void timedlock_with_deadlock_test() {
@@ -184,6 +216,12 @@ static void timedlock_with_deadlock_test() {
184216
ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_timedwrlock(&rwlock, &ts),
185217
ETIMEDOUT);
186218
ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_timedrdlock(&rwlock, &ts), 0);
219+
ASSERT_EQ(
220+
LIBC_NAMESPACE::pthread_rwlock_clockwrlock(&rwlock, CLOCK_MONOTONIC, &ts),
221+
ETIMEDOUT);
222+
ASSERT_EQ(
223+
LIBC_NAMESPACE::pthread_rwlock_clockrdlock(&rwlock, CLOCK_MONOTONIC, &ts),
224+
0);
187225
ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_unlock(&rwlock), 0);
188226
ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_unlock(&rwlock), 0);
189227
// notice that ts is already expired, but the following should still succeed.
@@ -270,9 +308,11 @@ enum class Operation : int {
270308
WRITE = 1,
271309
TIMED_READ = 2,
272310
TIMED_WRITE = 3,
273-
TRY_READ = 4,
274-
TRY_WRITE = 5,
275-
COUNT = 6
311+
CLOCK_READ = 4,
312+
CLOCK_WRITE = 5,
313+
TRY_READ = 6,
314+
TRY_WRITE = 7,
315+
COUNT = 8
276316
};
277317

278318
LIBC_NAMESPACE::RawMutex *io_mutex;
@@ -358,6 +398,24 @@ static void randomized_thread_operation(SharedData *data, ThreadGuard &guard) {
358398
}
359399
break;
360400
}
401+
case Operation::CLOCK_READ: {
402+
timespec ts = get_ts();
403+
if (LIBC_NAMESPACE::pthread_rwlock_clockrdlock(&data->lock, CLOCK_MONOTONIC,
404+
&ts) == 0) {
405+
read_ops();
406+
LIBC_NAMESPACE::pthread_rwlock_unlock(&data->lock);
407+
}
408+
break;
409+
}
410+
case Operation::CLOCK_WRITE: {
411+
timespec ts = get_ts();
412+
if (LIBC_NAMESPACE::pthread_rwlock_clockwrlock(&data->lock, CLOCK_MONOTONIC,
413+
&ts) == 0) {
414+
write_ops();
415+
LIBC_NAMESPACE::pthread_rwlock_unlock(&data->lock);
416+
}
417+
break;
418+
}
361419
case Operation::TRY_READ: {
362420
if (LIBC_NAMESPACE::pthread_rwlock_tryrdlock(&data->lock) == 0) {
363421
read_ops();

0 commit comments

Comments
 (0)