Skip to content

Commit 7934593

Browse files
committed
[libc] add pthread_rwlock_clockrdlock and pthread_rwlock_clockwrlock GNU extensions
1 parent 6907ab4 commit 7934593

File tree

10 files changed

+217
-3
lines changed

10 files changed

+217
-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/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: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
//===-- Implementation of the Rwlock's clockrdlock function
2+
//--------------------===//
3+
//
4+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5+
// See https://llvm.org/LICENSE.txt for license information.
6+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#include "src/pthread/pthread_rwlock_clockrdlock.h"
11+
12+
#include "src/__support/common.h"
13+
#include "src/__support/macros/config.h"
14+
#include "src/__support/threads/linux/rwlock.h"
15+
16+
#include <errno.h>
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_clockrdlock,
28+
(pthread_rwlock_t * rwlock, clockid_t clockid,
29+
const struct 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 && "clockrdlock 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->read_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 clockrdlock function -------*-
2+
// C++-*-===//
3+
//
4+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5+
// See https://llvm.org/LICENSE.txt for license information.
6+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#ifndef LLVM_LIBC_SRC_PTHREAD_PTHREAD_RWLOCK_CLOCKRDLOCK_H
11+
#define LLVM_LIBC_SRC_PTHREAD_PTHREAD_RWLOCK_CLOCKRDLOCK_H
12+
13+
#include "src/__support/macros/config.h"
14+
#include <pthread.h>
15+
16+
namespace LIBC_NAMESPACE_DECL {
17+
18+
int pthread_rwlock_clockrdlock(pthread_rwlock_t *rwlock, clockid_t clockid,
19+
const struct timespec *abstime);
20+
21+
} // namespace LIBC_NAMESPACE_DECL
22+
23+
#endif // LLVM_LIBC_SRC_PTHREAD_PTHREAD_RWLOCK_CLOCKRDLOCK_H
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
//===-- Implementation of the Rwlock's clockwrlock function
2+
//--------------------===//
3+
//
4+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5+
// See https://llvm.org/LICENSE.txt for license information.
6+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#include "src/pthread/pthread_rwlock_clockwrlock.h"
11+
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 <errno.h>
18+
#include <pthread.h>
19+
20+
namespace LIBC_NAMESPACE_DECL {
21+
22+
static_assert(
23+
sizeof(RwLock) == sizeof(pthread_rwlock_t) &&
24+
alignof(RwLock) == alignof(pthread_rwlock_t),
25+
"The public pthread_rwlock_t type must be of the same size and alignment "
26+
"as the internal rwlock type.");
27+
28+
LLVM_LIBC_FUNCTION(int, pthread_rwlock_clockwrlock,
29+
(pthread_rwlock_t * rwlock, clockid_t clockid,
30+
const struct timespec *abstime)) {
31+
if (!rwlock)
32+
return EINVAL;
33+
if (clockid != CLOCK_MONOTONIC && clockid != CLOCK_REALTIME)
34+
return EINVAL;
35+
bool is_realtime = (clockid == CLOCK_REALTIME);
36+
RwLock *rw = reinterpret_cast<RwLock *>(rwlock);
37+
LIBC_ASSERT(abstime && "clockwrlock called with a null timeout");
38+
auto timeout = internal::AbsTimeout::from_timespec(
39+
*abstime, /*is_realtime=*/is_realtime);
40+
if (LIBC_LIKELY(timeout.has_value()))
41+
return static_cast<int>(rw->write_lock(timeout.value()));
42+
43+
switch (timeout.error()) {
44+
case internal::AbsTimeout::Error::Invalid:
45+
return EINVAL;
46+
case internal::AbsTimeout::Error::BeforeEpoch:
47+
return ETIMEDOUT;
48+
}
49+
__builtin_unreachable();
50+
}
51+
52+
} // 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 -------*-
2+
// C++-*-===//
3+
//
4+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5+
// See https://llvm.org/LICENSE.txt for license information.
6+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#ifndef LLVM_LIBC_SRC_PTHREAD_PTHREAD_RWLOCK_CLOCKWRLOCK_H
11+
#define LLVM_LIBC_SRC_PTHREAD_PTHREAD_RWLOCK_CLOCKWRLOCK_H
12+
13+
#include "src/__support/macros/config.h"
14+
#include <pthread.h>
15+
16+
namespace LIBC_NAMESPACE_DECL {
17+
18+
int pthread_rwlock_clockwrlock(pthread_rwlock_t *rwlock, clockid_t clockid,
19+
const struct timespec *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: 38 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,8 @@ 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(LIBC_NAMESPACE::pthread_rwlock_clockrdlock(nullptr, &ts), EINVAL);
118+
ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_clockwrlock(nullptr, &ts), EINVAL);
115119
ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_tryrdlock(nullptr), EINVAL);
116120
ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_trywrlock(nullptr), EINVAL);
117121
ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_unlock(nullptr), EINVAL);
@@ -159,16 +163,26 @@ static void unusual_timespec_test() {
159163
timespec ts = {0, -1};
160164
ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_timedrdlock(&rwlock, &ts), EINVAL);
161165
ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_timedwrlock(&rwlock, &ts), EINVAL);
166+
ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_clockrdlock(&rwlock, &ts), EINVAL);
167+
ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_clockwrlock(&rwlock, &ts), EINVAL);
162168
ts.tv_nsec = 1'000'000'000;
163169
ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_timedrdlock(&rwlock, &ts), EINVAL);
170+
ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_clockrdlock(&rwlock, &ts), EINVAL);
171+
ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_clockwrlock(&rwlock, &ts), EINVAL);
164172
ts.tv_nsec += 1;
165173
ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_timedwrlock(&rwlock, &ts), EINVAL);
174+
ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_clockrdlock(&rwlock, &ts), EINVAL);
175+
ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_clockwrlock(&rwlock, &ts), EINVAL);
166176
ts.tv_nsec = 0;
167177
ts.tv_sec = -1;
168178
ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_timedrdlock(&rwlock, &ts),
169179
ETIMEDOUT);
170180
ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_timedwrlock(&rwlock, &ts),
171181
ETIMEDOUT);
182+
ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_clockrdlock(&rwlock, &ts),
183+
ETIMEDOUT);
184+
ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_clockwrlock(&rwlock, &ts),
185+
ETIMEDOUT);
172186
}
173187

174188
static void timedlock_with_deadlock_test() {
@@ -184,6 +198,9 @@ static void timedlock_with_deadlock_test() {
184198
ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_timedwrlock(&rwlock, &ts),
185199
ETIMEDOUT);
186200
ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_timedrdlock(&rwlock, &ts), 0);
201+
ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_clockwrlock(&rwlock, &ts),
202+
ETIMEDOUT);
203+
ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_clockrdlock(&rwlock, &ts), 0);
187204
ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_unlock(&rwlock), 0);
188205
ASSERT_EQ(LIBC_NAMESPACE::pthread_rwlock_unlock(&rwlock), 0);
189206
// notice that ts is already expired, but the following should still succeed.
@@ -270,9 +287,11 @@ enum class Operation : int {
270287
WRITE = 1,
271288
TIMED_READ = 2,
272289
TIMED_WRITE = 3,
273-
TRY_READ = 4,
274-
TRY_WRITE = 5,
275-
COUNT = 6
290+
CLOCK_READ = 4,
291+
CLOCK_WRITE = 5,
292+
TRY_READ = 6,
293+
TRY_WRITE = 7,
294+
COUNT = 8
276295
};
277296

278297
LIBC_NAMESPACE::RawMutex *io_mutex;
@@ -358,6 +377,22 @@ static void randomized_thread_operation(SharedData *data, ThreadGuard &guard) {
358377
}
359378
break;
360379
}
380+
case Operation::CLOCK_READ: {
381+
timespec ts = get_ts();
382+
if (LIBC_NAMESPACE::pthread_rwlock_clockrdlock(&data->lock, &ts) == 0) {
383+
read_ops();
384+
LIBC_NAMESPACE::pthread_rwlock_unlock(&data->lock);
385+
}
386+
break;
387+
}
388+
case Operation::CLOCK_WRITE: {
389+
timespec ts = get_ts();
390+
if (LIBC_NAMESPACE::pthread_rwlock_clockwrlock(&data->lock, &ts) == 0) {
391+
write_ops();
392+
LIBC_NAMESPACE::pthread_rwlock_unlock(&data->lock);
393+
}
394+
break;
395+
}
361396
case Operation::TRY_READ: {
362397
if (LIBC_NAMESPACE::pthread_rwlock_tryrdlock(&data->lock) == 0) {
363398
read_ops();

0 commit comments

Comments
 (0)