forked from OSchip/llvm-project
[libc] Add the pthread_mutex_t type.
Simple implementations of the functions pthread_mutex_init, pthread_mutex_destroy, pthread_mutex_lock and pthread_mutex_unlock have have also been added. Future patches will extend these functions to add features required by the POSIX specification. Reviewed By: lntue Differential Revision: https://reviews.llvm.org/D126235
This commit is contained in:
parent
239094cdee
commit
2a5d5078d5
|
@ -241,6 +241,7 @@ def ThreadsAPI : PublicAPI<"threads.h"> {
|
||||||
def PThreadAPI : PublicAPI<"pthread.h"> {
|
def PThreadAPI : PublicAPI<"pthread.h"> {
|
||||||
let Types = [
|
let Types = [
|
||||||
"pthread_attr_t",
|
"pthread_attr_t",
|
||||||
|
"pthread_mutex_t",
|
||||||
"pthread_mutexattr_t"
|
"pthread_mutexattr_t"
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
@ -236,6 +236,10 @@ if(LLVM_LIBC_FULL_BUILD)
|
||||||
libc.src.pthread.pthread_attr_setstack
|
libc.src.pthread.pthread_attr_setstack
|
||||||
libc.src.pthread.pthread_attr_setstacksize
|
libc.src.pthread.pthread_attr_setstacksize
|
||||||
libc.src.pthread.pthread_attr_init
|
libc.src.pthread.pthread_attr_init
|
||||||
|
libc.src.pthread.pthread_mutex_destroy
|
||||||
|
libc.src.pthread.pthread_mutex_init
|
||||||
|
libc.src.pthread.pthread_mutex_lock
|
||||||
|
libc.src.pthread.pthread_mutex_unlock
|
||||||
libc.src.pthread.pthread_mutexattr_destroy
|
libc.src.pthread.pthread_mutexattr_destroy
|
||||||
libc.src.pthread.pthread_mutexattr_init
|
libc.src.pthread.pthread_mutexattr_init
|
||||||
libc.src.pthread.pthread_mutexattr_getpshared
|
libc.src.pthread.pthread_mutexattr_getpshared
|
||||||
|
|
|
@ -163,6 +163,7 @@ add_gen_header(
|
||||||
DEPENDS
|
DEPENDS
|
||||||
.llvm_libc_common_h
|
.llvm_libc_common_h
|
||||||
.llvm-libc-types.pthread_attr_t
|
.llvm-libc-types.pthread_attr_t
|
||||||
|
.llvm-libc-types.pthread_mutex_t
|
||||||
.llvm-libc-types.pthread_mutexattr_t
|
.llvm-libc-types.pthread_mutexattr_t
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,8 @@ add_header(mtx_t HDR mtx_t.h DEPENDS .__futex_word .__mutex_type)
|
||||||
add_header(off_t HDR off_t.h)
|
add_header(off_t HDR off_t.h)
|
||||||
add_header(off64_t HDR off64_t.h)
|
add_header(off64_t HDR off64_t.h)
|
||||||
add_header(once_flag HDR once_flag.h DEPENDS .__futex_word)
|
add_header(once_flag HDR once_flag.h DEPENDS .__futex_word)
|
||||||
add_header(pthread_attr_t HDR pthread_attr_t.h)
|
add_header(pthread_attr_t HDR pthread_attr_t.h DEPENDS .size_t)
|
||||||
|
add_header(pthread_mutex_t HDR pthread_mutex_t.h DEPENDS .__futex_word .__mutex_type)
|
||||||
add_header(pthread_mutexattr_t HDR pthread_mutexattr_t.h)
|
add_header(pthread_mutexattr_t HDR pthread_mutexattr_t.h)
|
||||||
add_header(size_t HDR size_t.h)
|
add_header(size_t HDR size_t.h)
|
||||||
add_header(ssize_t HDR ssize_t.h)
|
add_header(ssize_t HDR ssize_t.h)
|
||||||
|
|
|
@ -6,6 +6,9 @@
|
||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#ifndef __LLVM_LIBC_TYPES___MUTEX_T_H
|
||||||
|
#define __LLVM_LIBC_TYPES___MUTEX_T_H
|
||||||
|
|
||||||
#include <llvm-libc-types/__futex_word.h>
|
#include <llvm-libc-types/__futex_word.h>
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -22,3 +25,5 @@ typedef struct {
|
||||||
#error "Mutex type not defined for the target platform."
|
#error "Mutex type not defined for the target platform."
|
||||||
#endif
|
#endif
|
||||||
} __mutex_type;
|
} __mutex_type;
|
||||||
|
|
||||||
|
#endif // __LLVM_LIBC_TYPES___MUTEX_T_H
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
//===-- Definition of pthread_mutex_t type --------------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#ifndef __LLVM_LIBC_TYPES_PTHREAD_MUTEX_T_H
|
||||||
|
#define __LLVM_LIBC_TYPES_PTHREAD_MUTEX_T_H
|
||||||
|
|
||||||
|
#include <llvm-libc-types/__mutex_type.h>
|
||||||
|
|
||||||
|
typedef __mutex_type pthread_mutex_t;
|
||||||
|
|
||||||
|
#endif // __LLVM_LIBC_TYPES_PTHREAD_MUTEX_T_H
|
|
@ -33,6 +33,12 @@ def POSIX : StandardSpec<"POSIX"> {
|
||||||
ConstType ConstPThreadMutexAttrTPtr = ConstType<PThreadMutexAttrTPtr>;
|
ConstType ConstPThreadMutexAttrTPtr = ConstType<PThreadMutexAttrTPtr>;
|
||||||
ConstType ConstRestrictedPThreadMutexAttrTPtr = ConstType<RestrictedPThreadMutexAttrTPtr>;
|
ConstType ConstRestrictedPThreadMutexAttrTPtr = ConstType<RestrictedPThreadMutexAttrTPtr>;
|
||||||
|
|
||||||
|
NamedType PThreadMutexTType = NamedType<"pthread_mutex_t">;
|
||||||
|
PtrType PThreadMutexTPtr = PtrType<PThreadMutexTType>;
|
||||||
|
RestrictedPtrType RestrictedPThreadMutexTPtr = RestrictedPtrType<PThreadMutexTType>;
|
||||||
|
ConstType ConstPThreadMutexTPtr = ConstType<PThreadMutexTPtr>;
|
||||||
|
ConstType ConstRestrictedPThreadMutexTPtr = ConstType<RestrictedPThreadMutexTPtr>;
|
||||||
|
|
||||||
HeaderSpec Errno = HeaderSpec<
|
HeaderSpec Errno = HeaderSpec<
|
||||||
"errno.h",
|
"errno.h",
|
||||||
[
|
[
|
||||||
|
@ -386,7 +392,7 @@ def POSIX : StandardSpec<"POSIX"> {
|
||||||
HeaderSpec PThread = HeaderSpec<
|
HeaderSpec PThread = HeaderSpec<
|
||||||
"pthread.h",
|
"pthread.h",
|
||||||
[], // Macros
|
[], // Macros
|
||||||
[PThreadAttrTType, PThreadMutexAttrTType], // Types
|
[PThreadAttrTType, PThreadMutexAttrTType, PThreadMutexTType], // Types
|
||||||
[], // Enumerations
|
[], // Enumerations
|
||||||
[
|
[
|
||||||
FunctionSpec<
|
FunctionSpec<
|
||||||
|
@ -499,6 +505,26 @@ def POSIX : StandardSpec<"POSIX"> {
|
||||||
RetValSpec<IntType>,
|
RetValSpec<IntType>,
|
||||||
[ArgSpec<RestrictedPThreadMutexAttrTPtr>, ArgSpec<IntType>]
|
[ArgSpec<RestrictedPThreadMutexAttrTPtr>, ArgSpec<IntType>]
|
||||||
>,
|
>,
|
||||||
|
FunctionSpec<
|
||||||
|
"pthread_mutex_init",
|
||||||
|
RetValSpec<IntType>,
|
||||||
|
[ArgSpec<RestrictedPThreadMutexTPtr>, ArgSpec<ConstRestrictedPThreadMutexAttrTPtr>]
|
||||||
|
>,
|
||||||
|
FunctionSpec<
|
||||||
|
"pthread_mutex_destroy",
|
||||||
|
RetValSpec<IntType>,
|
||||||
|
[ArgSpec<PThreadMutexTPtr>]
|
||||||
|
>,
|
||||||
|
FunctionSpec<
|
||||||
|
"pthread_mutex_lock",
|
||||||
|
RetValSpec<IntType>,
|
||||||
|
[ArgSpec<PThreadMutexTPtr>]
|
||||||
|
>,
|
||||||
|
FunctionSpec<
|
||||||
|
"pthread_mutex_unlock",
|
||||||
|
RetValSpec<IntType>,
|
||||||
|
[ArgSpec<PThreadMutexTPtr>]
|
||||||
|
>,
|
||||||
]
|
]
|
||||||
>;
|
>;
|
||||||
|
|
||||||
|
|
|
@ -196,3 +196,49 @@ add_entrypoint_object(
|
||||||
libc.include.errno
|
libc.include.errno
|
||||||
libc.include.pthread
|
libc.include.pthread
|
||||||
)
|
)
|
||||||
|
|
||||||
|
add_entrypoint_object(
|
||||||
|
pthread_mutex_init
|
||||||
|
SRCS
|
||||||
|
pthread_mutex_init.cpp
|
||||||
|
HDRS
|
||||||
|
pthread_mutex_init.h
|
||||||
|
DEPENDS
|
||||||
|
.pthread_mutexattr
|
||||||
|
libc.include.errno
|
||||||
|
libc.include.pthread
|
||||||
|
libc.src.__support.threads.mutex
|
||||||
|
)
|
||||||
|
|
||||||
|
add_entrypoint_object(
|
||||||
|
pthread_mutex_destroy
|
||||||
|
SRCS
|
||||||
|
pthread_mutex_destroy.cpp
|
||||||
|
HDRS
|
||||||
|
pthread_mutex_destroy.h
|
||||||
|
DEPENDS
|
||||||
|
libc.include.pthread
|
||||||
|
libc.src.__support.threads.mutex
|
||||||
|
)
|
||||||
|
|
||||||
|
add_entrypoint_object(
|
||||||
|
pthread_mutex_lock
|
||||||
|
SRCS
|
||||||
|
pthread_mutex_lock.cpp
|
||||||
|
HDRS
|
||||||
|
pthread_mutex_lock.h
|
||||||
|
DEPENDS
|
||||||
|
libc.include.pthread
|
||||||
|
libc.src.__support.threads.mutex
|
||||||
|
)
|
||||||
|
|
||||||
|
add_entrypoint_object(
|
||||||
|
pthread_mutex_unlock
|
||||||
|
SRCS
|
||||||
|
pthread_mutex_unlock.cpp
|
||||||
|
HDRS
|
||||||
|
pthread_mutex_unlock.h
|
||||||
|
DEPENDS
|
||||||
|
libc.include.pthread
|
||||||
|
libc.src.__support.threads.mutex
|
||||||
|
)
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
//===-- Linux implementation of the pthread_mutex_destroy function --------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "pthread_mutex_destroy.h"
|
||||||
|
|
||||||
|
#include "src/__support/common.h"
|
||||||
|
#include "src/__support/threads/mutex.h"
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
namespace __llvm_libc {
|
||||||
|
|
||||||
|
LLVM_LIBC_FUNCTION(int, pthread_mutex_destroy, (pthread_mutex_t * mutex)) {
|
||||||
|
auto *m = reinterpret_cast<Mutex *>(mutex);
|
||||||
|
Mutex::destroy(m);
|
||||||
|
// TODO: When the Mutex class supports all the possible error conditions
|
||||||
|
// return the appropriate error value here.
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace __llvm_libc
|
|
@ -0,0 +1,20 @@
|
||||||
|
//===-- Implementation header for pthread_mutex_destroy ---------*- C++ -*-===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#ifndef LLVM_LIBC_SRC_PTHREAD_PTHREAD_MUTEX__DESTROY_H
|
||||||
|
#define LLVM_LIBC_SRC_PTHREAD_PTHREAD_MUTEX__DESTROY_H
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
namespace __llvm_libc {
|
||||||
|
|
||||||
|
int pthread_mutex_destroy(pthread_mutex_t *mutex);
|
||||||
|
|
||||||
|
} // namespace __llvm_libc
|
||||||
|
|
||||||
|
#endif // LLVM_LIBC_SRC_PTHREAD_PTHREAD_MUTEX_DESTROY_H
|
|
@ -0,0 +1,35 @@
|
||||||
|
//===-- Linux implementation of the pthread_mutex_init function -----------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "pthread_mutex_init.h"
|
||||||
|
#include "pthread_mutexattr.h"
|
||||||
|
|
||||||
|
#include "src/__support/common.h"
|
||||||
|
#include "src/__support/threads/mutex.h"
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
namespace __llvm_libc {
|
||||||
|
|
||||||
|
static_assert(sizeof(Mutex) <= sizeof(pthread_mutex_t),
|
||||||
|
"The public pthread_mutex_t type cannot accommodate the internal "
|
||||||
|
"mutex type.");
|
||||||
|
|
||||||
|
LLVM_LIBC_FUNCTION(int, pthread_mutex_init,
|
||||||
|
(pthread_mutex_t * m,
|
||||||
|
const pthread_mutexattr_t *__restrict attr)) {
|
||||||
|
auto mutexattr = attr == nullptr ? DEFAULT_MUTEXATTR : *attr;
|
||||||
|
auto err =
|
||||||
|
Mutex::init(reinterpret_cast<Mutex *>(m), false,
|
||||||
|
get_mutexattr_type(mutexattr) & PTHREAD_MUTEX_RECURSIVE,
|
||||||
|
get_mutexattr_robust(mutexattr) & PTHREAD_MUTEX_ROBUST);
|
||||||
|
return err == MutexError::NONE ? 0 : EAGAIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace __llvm_libc
|
|
@ -0,0 +1,21 @@
|
||||||
|
//===-- Implementation header for pthread_mutex_init function ---*- C++ -*-===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#ifndef LLVM_LIBC_SRC_PTHREAD_PTHREAD_MUTEX_INIT_H
|
||||||
|
#define LLVM_LIBC_SRC_PTHREAD_PTHREAD_MUTEX_INIT_H
|
||||||
|
|
||||||
|
#include "include/pthread.h"
|
||||||
|
|
||||||
|
namespace __llvm_libc {
|
||||||
|
|
||||||
|
int pthread_mutex_init(pthread_mutex_t *mutex,
|
||||||
|
const pthread_mutexattr_t *__restrict attr);
|
||||||
|
|
||||||
|
} // namespace __llvm_libc
|
||||||
|
|
||||||
|
#endif // LLVM_LIBC_SRC_PTHREAD_pthread_mutex_INIT_H
|
|
@ -0,0 +1,26 @@
|
||||||
|
//===-- Linux implementation of the pthread_mutex_lock function -----------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "pthread_mutex_lock.h"
|
||||||
|
|
||||||
|
#include "src/__support/common.h"
|
||||||
|
#include "src/__support/threads/mutex.h"
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
namespace __llvm_libc {
|
||||||
|
|
||||||
|
// The implementation currently handles only plain mutexes.
|
||||||
|
LLVM_LIBC_FUNCTION(int, pthread_mutex_lock, (pthread_mutex_t * mutex)) {
|
||||||
|
reinterpret_cast<Mutex *>(mutex)->lock();
|
||||||
|
// TODO: When the Mutex class supports all the possible error conditions
|
||||||
|
// return the appropriate error value here.
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace __llvm_libc
|
|
@ -0,0 +1,20 @@
|
||||||
|
//===-- Implementation header for pthread_mutex_lock function ---*- C++ -*-===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#ifndef LLVM_LIBC_SRC_PTHREAD_PTHREAD_MUTEX_LOCK_H
|
||||||
|
#define LLVM_LIBC_SRC_PTHREAD_PTHREAD_MUTEX_LOCK_H
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
namespace __llvm_libc {
|
||||||
|
|
||||||
|
int pthread_mutex_lock(pthread_mutex_t *mutex);
|
||||||
|
|
||||||
|
} // namespace __llvm_libc
|
||||||
|
|
||||||
|
#endif // LLVM_LIBC_SRC_PTHREAD_PTHREAD_MUTEX_LOCK_H
|
|
@ -0,0 +1,26 @@
|
||||||
|
//===-- Linux implementation of the pthread_mutex_unlock function ---------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "pthread_mutex_unlock.h"
|
||||||
|
|
||||||
|
#include "src/__support/common.h"
|
||||||
|
#include "src/__support/threads/mutex.h"
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
namespace __llvm_libc {
|
||||||
|
|
||||||
|
// The implementation currently handles only plain mutexes.
|
||||||
|
LLVM_LIBC_FUNCTION(int, pthread_mutex_unlock, (pthread_mutex_t * mutex)) {
|
||||||
|
reinterpret_cast<Mutex *>(mutex)->unlock();
|
||||||
|
// TODO: When the Mutex class supports all the possible error conditions
|
||||||
|
// return the appropriate error value here.
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace __llvm_libc
|
|
@ -0,0 +1,20 @@
|
||||||
|
//===-- Implementation header for pthread_mutex_unlock function -*- C++ -*-===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#ifndef LLVM_LIBC_SRC_PTHREAD_PTHREAD_MUTEX_UNLOCK_H
|
||||||
|
#define LLVM_LIBC_SRC_PTHREAD_PTHREAD_MUTEX_UNLOCK_H
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
namespace __llvm_libc {
|
||||||
|
|
||||||
|
int pthread_mutex_unlock(pthread_mutex_t *mutex);
|
||||||
|
|
||||||
|
} // namespace __llvm_libc
|
||||||
|
|
||||||
|
#endif // LLVM_LIBC_SRC_PTHREAD_PTHREAD_MUTEX_UNLOCK_H
|
|
@ -31,6 +31,16 @@ constexpr pthread_mutexattr_t DEFAULT_MUTEXATTR =
|
||||||
PTHREAD_MUTEX_STALLED << unsigned(PThreadMutexAttrPos::ROBUST_SHIFT) |
|
PTHREAD_MUTEX_STALLED << unsigned(PThreadMutexAttrPos::ROBUST_SHIFT) |
|
||||||
PTHREAD_PROCESS_PRIVATE << unsigned(PThreadMutexAttrPos::PSHARED_SHIFT);
|
PTHREAD_PROCESS_PRIVATE << unsigned(PThreadMutexAttrPos::PSHARED_SHIFT);
|
||||||
|
|
||||||
|
static inline int get_mutexattr_type(pthread_mutexattr_t attr) {
|
||||||
|
return (attr & unsigned(PThreadMutexAttrPos::TYPE_MASK)) >>
|
||||||
|
unsigned(PThreadMutexAttrPos::TYPE_SHIFT);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int get_mutexattr_robust(pthread_mutexattr_t attr) {
|
||||||
|
return (attr & unsigned(PThreadMutexAttrPos::ROBUST_MASK)) >>
|
||||||
|
unsigned(PThreadMutexAttrPos::ROBUST_SHIFT);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace __llvm_libc
|
} // namespace __llvm_libc
|
||||||
|
|
||||||
#endif // LLVM_LIBC_SRC_PTHREAD_PTHREAD_MUTEXATTR_H
|
#endif // LLVM_LIBC_SRC_PTHREAD_PTHREAD_MUTEXATTR_H
|
||||||
|
|
|
@ -39,3 +39,20 @@ add_libc_unittest(
|
||||||
libc.src.pthread.pthread_mutexattr_setrobust
|
libc.src.pthread.pthread_mutexattr_setrobust
|
||||||
libc.src.pthread.pthread_mutexattr_settype
|
libc.src.pthread.pthread_mutexattr_settype
|
||||||
)
|
)
|
||||||
|
|
||||||
|
add_libc_unittest(
|
||||||
|
phtread_mutex_test
|
||||||
|
SUITE
|
||||||
|
libc_pthread_unittests
|
||||||
|
SRCS
|
||||||
|
pthread_mutex_test.cpp
|
||||||
|
DEPENDS
|
||||||
|
libc.include.pthread
|
||||||
|
libc.src.errno.errno
|
||||||
|
libc.src.pthread.pthread_mutex_destroy
|
||||||
|
libc.src.pthread.pthread_mutex_init
|
||||||
|
libc.src.pthread.pthread_mutex_lock
|
||||||
|
libc.src.pthread.pthread_mutex_unlock
|
||||||
|
libc.src.threads.thrd_create
|
||||||
|
libc.src.threads.thrd_join
|
||||||
|
)
|
||||||
|
|
|
@ -0,0 +1,188 @@
|
||||||
|
//===-- Unittests for pthread_mutex_t -------------------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "src/pthread/pthread_mutex_destroy.h"
|
||||||
|
#include "src/pthread/pthread_mutex_init.h"
|
||||||
|
#include "src/pthread/pthread_mutex_lock.h"
|
||||||
|
#include "src/pthread/pthread_mutex_unlock.h"
|
||||||
|
|
||||||
|
// TODO: When pthread_t type is available, use it to spawn threads instead of
|
||||||
|
// thrd_t.
|
||||||
|
#include "src/threads/thrd_create.h"
|
||||||
|
#include "src/threads/thrd_join.h"
|
||||||
|
|
||||||
|
#include "utils/UnitTest/Test.h"
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
constexpr int START = 0;
|
||||||
|
constexpr int MAX = 10000;
|
||||||
|
|
||||||
|
pthread_mutex_t mutex;
|
||||||
|
static int shared_int = START;
|
||||||
|
|
||||||
|
int counter(void *arg) {
|
||||||
|
int last_count = START;
|
||||||
|
while (true) {
|
||||||
|
__llvm_libc::pthread_mutex_lock(&mutex);
|
||||||
|
if (shared_int == last_count + 1) {
|
||||||
|
shared_int++;
|
||||||
|
last_count = shared_int;
|
||||||
|
}
|
||||||
|
__llvm_libc::pthread_mutex_unlock(&mutex);
|
||||||
|
if (last_count >= MAX)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(LlvmLibcMutexTest, RelayCounter) {
|
||||||
|
ASSERT_EQ(__llvm_libc::pthread_mutex_init(&mutex, nullptr), 0);
|
||||||
|
|
||||||
|
// The idea of this test is that two competing threads will update
|
||||||
|
// a counter only if the other thread has updated it.
|
||||||
|
thrd_t thread;
|
||||||
|
__llvm_libc::thrd_create(&thread, counter, nullptr);
|
||||||
|
|
||||||
|
int last_count = START;
|
||||||
|
while (true) {
|
||||||
|
ASSERT_EQ(__llvm_libc::pthread_mutex_lock(&mutex), 0);
|
||||||
|
if (shared_int == START) {
|
||||||
|
++shared_int;
|
||||||
|
last_count = shared_int;
|
||||||
|
} else if (shared_int != last_count) {
|
||||||
|
ASSERT_EQ(shared_int, last_count + 1);
|
||||||
|
++shared_int;
|
||||||
|
last_count = shared_int;
|
||||||
|
}
|
||||||
|
ASSERT_EQ(__llvm_libc::pthread_mutex_unlock(&mutex), 0);
|
||||||
|
if (last_count > MAX)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
int retval = 123;
|
||||||
|
__llvm_libc::thrd_join(&thread, &retval);
|
||||||
|
ASSERT_EQ(retval, 0);
|
||||||
|
|
||||||
|
__llvm_libc::pthread_mutex_destroy(&mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_mutex_t start_lock, step_lock;
|
||||||
|
bool started, step;
|
||||||
|
|
||||||
|
int stepper(void *arg) {
|
||||||
|
__llvm_libc::pthread_mutex_lock(&start_lock);
|
||||||
|
started = true;
|
||||||
|
__llvm_libc::pthread_mutex_unlock(&start_lock);
|
||||||
|
|
||||||
|
__llvm_libc::pthread_mutex_lock(&step_lock);
|
||||||
|
step = true;
|
||||||
|
__llvm_libc::pthread_mutex_unlock(&step_lock);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(LlvmLibcMutexTest, WaitAndStep) {
|
||||||
|
ASSERT_EQ(__llvm_libc::pthread_mutex_init(&start_lock, nullptr), 0);
|
||||||
|
ASSERT_EQ(__llvm_libc::pthread_mutex_init(&step_lock, nullptr), 0);
|
||||||
|
|
||||||
|
// In this test, we start a new thread but block it before it can make a
|
||||||
|
// step. Once we ensure that the thread is blocked, we unblock it.
|
||||||
|
// After unblocking, we then verify that the thread was indeed unblocked.
|
||||||
|
step = false;
|
||||||
|
started = false;
|
||||||
|
ASSERT_EQ(__llvm_libc::pthread_mutex_lock(&step_lock), 0);
|
||||||
|
|
||||||
|
thrd_t thread;
|
||||||
|
__llvm_libc::thrd_create(&thread, stepper, nullptr);
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
// Make sure the thread actually started.
|
||||||
|
ASSERT_EQ(__llvm_libc::pthread_mutex_lock(&start_lock), 0);
|
||||||
|
bool s = started;
|
||||||
|
ASSERT_EQ(__llvm_libc::pthread_mutex_unlock(&start_lock), 0);
|
||||||
|
if (s)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Since |step_lock| is still locked, |step| should be false.
|
||||||
|
ASSERT_FALSE(step);
|
||||||
|
|
||||||
|
// Unlock the step lock and wait until the step is made.
|
||||||
|
ASSERT_EQ(__llvm_libc::pthread_mutex_unlock(&step_lock), 0);
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
ASSERT_EQ(__llvm_libc::pthread_mutex_lock(&step_lock), 0);
|
||||||
|
bool current_step_value = step;
|
||||||
|
ASSERT_EQ(__llvm_libc::pthread_mutex_unlock(&step_lock), 0);
|
||||||
|
if (current_step_value)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
int retval = 123;
|
||||||
|
__llvm_libc::thrd_join(&thread, &retval);
|
||||||
|
ASSERT_EQ(retval, 0);
|
||||||
|
|
||||||
|
__llvm_libc::pthread_mutex_destroy(&start_lock);
|
||||||
|
__llvm_libc::pthread_mutex_destroy(&step_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr int THREAD_COUNT = 10;
|
||||||
|
static pthread_mutex_t multiple_waiter_lock;
|
||||||
|
static pthread_mutex_t counter_lock;
|
||||||
|
static int wait_count = 0;
|
||||||
|
|
||||||
|
int waiter_func(void *) {
|
||||||
|
__llvm_libc::pthread_mutex_lock(&counter_lock);
|
||||||
|
++wait_count;
|
||||||
|
__llvm_libc::pthread_mutex_unlock(&counter_lock);
|
||||||
|
|
||||||
|
// Block on the waiter lock until the main
|
||||||
|
// thread unblocks.
|
||||||
|
__llvm_libc::pthread_mutex_lock(&multiple_waiter_lock);
|
||||||
|
__llvm_libc::pthread_mutex_unlock(&multiple_waiter_lock);
|
||||||
|
|
||||||
|
__llvm_libc::pthread_mutex_lock(&counter_lock);
|
||||||
|
--wait_count;
|
||||||
|
__llvm_libc::pthread_mutex_unlock(&counter_lock);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(LlvmLibcMutexTest, MultipleWaiters) {
|
||||||
|
__llvm_libc::pthread_mutex_init(&multiple_waiter_lock, nullptr);
|
||||||
|
__llvm_libc::pthread_mutex_init(&counter_lock, nullptr);
|
||||||
|
|
||||||
|
__llvm_libc::pthread_mutex_lock(&multiple_waiter_lock);
|
||||||
|
thrd_t waiters[THREAD_COUNT];
|
||||||
|
for (int i = 0; i < THREAD_COUNT; ++i) {
|
||||||
|
__llvm_libc::thrd_create(waiters + i, waiter_func, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Spin until the counter is incremented to the desired
|
||||||
|
// value.
|
||||||
|
while (true) {
|
||||||
|
__llvm_libc::pthread_mutex_lock(&counter_lock);
|
||||||
|
if (wait_count == THREAD_COUNT) {
|
||||||
|
__llvm_libc::pthread_mutex_unlock(&counter_lock);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
__llvm_libc::pthread_mutex_unlock(&counter_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
__llvm_libc::pthread_mutex_unlock(&multiple_waiter_lock);
|
||||||
|
|
||||||
|
int retval;
|
||||||
|
for (int i = 0; i < THREAD_COUNT; ++i) {
|
||||||
|
__llvm_libc::thrd_join(waiters + i, &retval);
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT_EQ(wait_count, 0);
|
||||||
|
|
||||||
|
__llvm_libc::pthread_mutex_destroy(&multiple_waiter_lock);
|
||||||
|
__llvm_libc::pthread_mutex_destroy(&counter_lock);
|
||||||
|
}
|
Loading…
Reference in New Issue