diff options
author | Samuel Thibault <samuel.thibault@ens-lyon.org> | 2020-01-13 19:58:28 +0000 |
---|---|---|
committer | Samuel Thibault <samuel.thibault@ens-lyon.org> | 2020-02-09 13:56:48 +0100 |
commit | b05de1040009d0d07a5a2e2765cffe554ffbe6ac (patch) | |
tree | 2b112a97ce7947699fac8b6df47e6db0b5196ded /sysdeps/pthread | |
parent | htl: Add C11 threads types definitions (diff) | |
download | glibc-b05de1040009d0d07a5a2e2765cffe554ffbe6ac.tar.gz glibc-b05de1040009d0d07a5a2e2765cffe554ffbe6ac.tar.bz2 glibc-b05de1040009d0d07a5a2e2765cffe554ffbe6ac.zip |
C11 threads: Move implementation to sysdeps/pthread
so it gets shared by nptl and htl. Also add htl versions of thrd_current and
thrd_yield.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Diffstat (limited to 'sysdeps/pthread')
37 files changed, 1749 insertions, 0 deletions
diff --git a/sysdeps/pthread/Makefile b/sysdeps/pthread/Makefile index 7f9eadd0e2..889f10d8b1 100644 --- a/sysdeps/pthread/Makefile +++ b/sysdeps/pthread/Makefile @@ -25,3 +25,21 @@ $(objpfx)tst-timer: $(objpfx)librt.a $(static-thread-library) endif endif + +ifneq (,$(filter $(subdir),htl nptl)) +headers += threads.h + +routines += thrd_current thrd_equal thrd_sleep thrd_yield + +libpthread-routines += thrd_create thrd_detach thrd_exit thrd_join \ + call_once \ + mtx_destroy mtx_init mtx_lock mtx_timedlock \ + mtx_trylock mtx_unlock \ + cnd_broadcast \ + cnd_destroy cnd_init cnd_signal cnd_timedwait cnd_wait \ + tss_create tss_delete tss_get tss_set + +tests += tst-cnd-basic tst-mtx-trylock tst-cnd-broadcast \ + tst-cnd-timedwait tst-thrd-detach tst-mtx-basic tst-thrd-sleep \ + tst-mtx-recursive tst-tss-basic tst-call-once tst-mtx-timedlock +endif diff --git a/sysdeps/pthread/call_once.c b/sysdeps/pthread/call_once.c new file mode 100644 index 0000000000..25e2964c76 --- /dev/null +++ b/sysdeps/pthread/call_once.c @@ -0,0 +1,31 @@ +/* C11 threads call once implementation. + Copyright (C) 2018-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include <stdalign.h> + +#include "thrd_priv.h" + +void +call_once (once_flag *flag, void (*func)(void)) +{ + _Static_assert (sizeof (once_flag) == sizeof (pthread_once_t), + "sizeof (once_flag) != sizeof (pthread_once_t)"); + _Static_assert (alignof (once_flag) == alignof (pthread_once_t), + "alignof (once_flag) != alignof (pthread_once_t)"); + __pthread_once ((pthread_once_t *) flag, func); +} diff --git a/sysdeps/pthread/cnd_broadcast.c b/sysdeps/pthread/cnd_broadcast.c new file mode 100644 index 0000000000..66e0fce0c6 --- /dev/null +++ b/sysdeps/pthread/cnd_broadcast.c @@ -0,0 +1,26 @@ +/* C11 thread conditional broadcast implementation. + Copyright (C) 2018-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include "thrd_priv.h" + +int +cnd_broadcast (cnd_t *cond) +{ + int err_code = __pthread_cond_broadcast ((pthread_cond_t*) cond); + return thrd_err_map (err_code); +} diff --git a/sysdeps/pthread/cnd_destroy.c b/sysdeps/pthread/cnd_destroy.c new file mode 100644 index 0000000000..763e91cb0f --- /dev/null +++ b/sysdeps/pthread/cnd_destroy.c @@ -0,0 +1,26 @@ +/* C11 threads conditional destroy implementation. + Copyright (C) 2018-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include "thrd_priv.h" +#include "pthreadP.h" + +void +cnd_destroy (cnd_t *cond) +{ + __pthread_cond_destroy ((pthread_cond_t *) cond); +} diff --git a/sysdeps/pthread/cnd_init.c b/sysdeps/pthread/cnd_init.c new file mode 100644 index 0000000000..e8d7d68a2c --- /dev/null +++ b/sysdeps/pthread/cnd_init.c @@ -0,0 +1,33 @@ +/* C11 thread conditional initialization implementation. + Copyright (C) 2018-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include <stdalign.h> + +#include "thrd_priv.h" + +int +cnd_init (cnd_t *cond) +{ + _Static_assert (sizeof (cnd_t) == sizeof (pthread_cond_t), + "(sizeof (cnd_t) != sizeof (pthread_cond_t)"); + _Static_assert (alignof (cnd_t) == alignof (pthread_cond_t), + "alignof (cnd_t) != alignof (pthread_cond_t)"); + + int err_code = __pthread_cond_init ((pthread_cond_t *)cond, NULL); + return thrd_err_map (err_code); +} diff --git a/sysdeps/pthread/cnd_signal.c b/sysdeps/pthread/cnd_signal.c new file mode 100644 index 0000000000..27155ffc1b --- /dev/null +++ b/sysdeps/pthread/cnd_signal.c @@ -0,0 +1,26 @@ +/* C11 threads conditional signal implementation. + Copyright (C) 2018-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include "thrd_priv.h" + +int +cnd_signal (cnd_t *cond) +{ + int err_code = __pthread_cond_signal ((pthread_cond_t *) cond); + return thrd_err_map (err_code); +} diff --git a/sysdeps/pthread/cnd_timedwait.c b/sysdeps/pthread/cnd_timedwait.c new file mode 100644 index 0000000000..c7f5309cf7 --- /dev/null +++ b/sysdeps/pthread/cnd_timedwait.c @@ -0,0 +1,29 @@ +/* C11 threads conditional timed wait implementation. + Copyright (C) 2018-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include "thrd_priv.h" + +int +cnd_timedwait (cnd_t *restrict cond, mtx_t *restrict mutex, + const struct timespec* restrict time_point) +{ + int err_code = __pthread_cond_timedwait ((pthread_cond_t *) cond, + (pthread_mutex_t *) mutex, + time_point); + return thrd_err_map (err_code); +} diff --git a/sysdeps/pthread/cnd_wait.c b/sysdeps/pthread/cnd_wait.c new file mode 100644 index 0000000000..8070ca7c6a --- /dev/null +++ b/sysdeps/pthread/cnd_wait.c @@ -0,0 +1,27 @@ +/* C11 threads conditional wait implementaiton. + Copyright (C) 2018-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include "thrd_priv.h" + +int +cnd_wait (cnd_t *cond, mtx_t *mutex) +{ + int err_code = __pthread_cond_wait ((pthread_cond_t *) cond, + (pthread_mutex_t *) mutex); + return thrd_err_map (err_code); +} diff --git a/sysdeps/pthread/mtx_destroy.c b/sysdeps/pthread/mtx_destroy.c new file mode 100644 index 0000000000..9ac324c8f8 --- /dev/null +++ b/sysdeps/pthread/mtx_destroy.c @@ -0,0 +1,26 @@ +/* C11 threads mutex destroy implementation. + Copyright (C) 2018-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include "thrd_priv.h" +#include "pthreadP.h" + +void +mtx_destroy (mtx_t *mutex) +{ + __pthread_mutex_destroy ((pthread_mutex_t *) mutex); +} diff --git a/sysdeps/pthread/mtx_init.c b/sysdeps/pthread/mtx_init.c new file mode 100644 index 0000000000..436a03673e --- /dev/null +++ b/sysdeps/pthread/mtx_init.c @@ -0,0 +1,53 @@ +/* C11 threads mutex initialization implementation. + Copyright (C) 2018-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include <stdalign.h> + +#include "thrd_priv.h" + +int +mtx_init (mtx_t *mutex, int type) +{ + _Static_assert (sizeof (mtx_t) == sizeof (pthread_mutex_t), + "sizeof (mtx_t) != sizeof (pthread_mutex_t)"); + _Static_assert (alignof (mtx_t) == alignof (pthread_mutex_t), + "alignof (mtx_t) != alignof (pthread_mutex_t)"); + + pthread_mutexattr_t attr; + + __pthread_mutexattr_init (&attr); + + /* Another possible solution would be to set the flags directly in + mutex object. */ + switch (type) + { + case mtx_plain | mtx_recursive: + case mtx_timed | mtx_recursive: + __pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE); + break; + case mtx_plain: + case mtx_timed: /* No difference between both in standard */ + default: + __pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_NORMAL); + break; + } + + int err_code = __pthread_mutex_init ((pthread_mutex_t *) mutex, &attr); + /* pthread_mutexattr_destroy implementation is a noop. */ + return thrd_err_map (err_code); +} diff --git a/sysdeps/pthread/mtx_lock.c b/sysdeps/pthread/mtx_lock.c new file mode 100644 index 0000000000..cf1632b3f2 --- /dev/null +++ b/sysdeps/pthread/mtx_lock.c @@ -0,0 +1,26 @@ +/* C11 threads mutex lock implementation. + Copyright (C) 2018-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include "thrd_priv.h" + +int +mtx_lock (mtx_t *mutex) +{ + int err_code = __pthread_mutex_lock ((pthread_mutex_t *) mutex); + return thrd_err_map (err_code); +} diff --git a/sysdeps/pthread/mtx_timedlock.c b/sysdeps/pthread/mtx_timedlock.c new file mode 100644 index 0000000000..d55cf99d11 --- /dev/null +++ b/sysdeps/pthread/mtx_timedlock.c @@ -0,0 +1,28 @@ +/* C11 threads mutex timed lock implementation. + Copyright (C) 2018-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include "thrd_priv.h" + +int +mtx_timedlock (mtx_t *restrict mutex, + const struct timespec *restrict time_point) +{ + int err_code = __pthread_mutex_timedlock ((pthread_mutex_t *)mutex, + time_point); + return thrd_err_map (err_code); +} diff --git a/sysdeps/pthread/mtx_trylock.c b/sysdeps/pthread/mtx_trylock.c new file mode 100644 index 0000000000..7ffcbc1e93 --- /dev/null +++ b/sysdeps/pthread/mtx_trylock.c @@ -0,0 +1,26 @@ +/* C11 threads mutex try lock implementation. + Copyright (C) 2018-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include "thrd_priv.h" + +int +mtx_trylock (mtx_t *mutex) +{ + int err_code = __pthread_mutex_trylock ((pthread_mutex_t *) mutex); + return thrd_err_map (err_code); +} diff --git a/sysdeps/pthread/mtx_unlock.c b/sysdeps/pthread/mtx_unlock.c new file mode 100644 index 0000000000..ebb0cd633b --- /dev/null +++ b/sysdeps/pthread/mtx_unlock.c @@ -0,0 +1,26 @@ +/* C11 threads mutex unlock implementation. + Copyright (C) 2018-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include "thrd_priv.h" + +int +mtx_unlock (mtx_t *mutex) +{ + int err_code = __pthread_mutex_unlock ((pthread_mutex_t *) mutex); + return thrd_err_map (err_code); +} diff --git a/sysdeps/pthread/thrd_create.c b/sysdeps/pthread/thrd_create.c new file mode 100644 index 0000000000..4c47f053af --- /dev/null +++ b/sysdeps/pthread/thrd_create.c @@ -0,0 +1,30 @@ +/* C11 threads thread creation implementation. + Copyright (C) 2018-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include "thrd_priv.h" + +int +thrd_create (thrd_t *thr, thrd_start_t func, void *arg) +{ + _Static_assert (sizeof (thrd_t) == sizeof (pthread_t), + "sizeof (thrd_t) != sizeof (pthread_t)"); + + int err_code = __pthread_create (thr, ATTR_C11_THREAD, + (void* (*) (void*))func, arg); + return thrd_err_map (err_code); +} diff --git a/sysdeps/pthread/thrd_detach.c b/sysdeps/pthread/thrd_detach.c new file mode 100644 index 0000000000..8ddc2e8477 --- /dev/null +++ b/sysdeps/pthread/thrd_detach.c @@ -0,0 +1,28 @@ +/* C11 threads thread detach implementation. + Copyright (C) 2018-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include "thrd_priv.h" + +int +thrd_detach (thrd_t thr) +{ + int err_code; + + err_code = __pthread_detach (thr); + return thrd_err_map (err_code); +} diff --git a/sysdeps/pthread/thrd_equal.c b/sysdeps/pthread/thrd_equal.c new file mode 100644 index 0000000000..41211d3ef9 --- /dev/null +++ b/sysdeps/pthread/thrd_equal.c @@ -0,0 +1,25 @@ +/* C11 threads thread equality check implementation. + Copyright (C) 2018-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include "thrd_priv.h" + +int +thrd_equal (thrd_t lhs, thrd_t rhs) +{ + return lhs == rhs; +} diff --git a/sysdeps/pthread/thrd_exit.c b/sysdeps/pthread/thrd_exit.c new file mode 100644 index 0000000000..d9ad207baa --- /dev/null +++ b/sysdeps/pthread/thrd_exit.c @@ -0,0 +1,25 @@ +/* C11 threads thread exit implementation. + Copyright (C) 2018-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include "thrd_priv.h" + +_Noreturn void +thrd_exit (int res) +{ + __pthread_exit ((void*)(uintptr_t) res); +} diff --git a/sysdeps/pthread/thrd_join.c b/sysdeps/pthread/thrd_join.c new file mode 100644 index 0000000000..0c482959d5 --- /dev/null +++ b/sysdeps/pthread/thrd_join.c @@ -0,0 +1,30 @@ +/* C11 threads thread join implementation. + Copyright (C) 2018-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include "thrd_priv.h" + +int +thrd_join (thrd_t thr, int *res) +{ + void *pthread_res; + int err_code = __pthread_join (thr, &pthread_res); + if (res) + *res = (int) (uintptr_t) pthread_res; + + return thrd_err_map (err_code); +} diff --git a/sysdeps/pthread/thrd_priv.h b/sysdeps/pthread/thrd_priv.h new file mode 100644 index 0000000000..d22ad6f632 --- /dev/null +++ b/sysdeps/pthread/thrd_priv.h @@ -0,0 +1,45 @@ +/* Internal C11 threads definitions. + Copyright (C) 2018-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#ifndef THRD_PRIV_H +# define THRD_PRIV_H + +#include <features.h> +#include <threads.h> +#include <errno.h> +#include "pthreadP.h" /* For pthread_{mutex,cond}_t definitions. */ + +static __always_inline int +thrd_err_map (int err_code) +{ + switch (err_code) + { + case 0: + return thrd_success; + case ENOMEM: + return thrd_nomem; + case ETIMEDOUT: + return thrd_timedout; + case EBUSY: + return thrd_busy; + default: + return thrd_error; + } +} + +#endif diff --git a/sysdeps/pthread/thrd_sleep.c b/sysdeps/pthread/thrd_sleep.c new file mode 100644 index 0000000000..c9805d5fd1 --- /dev/null +++ b/sysdeps/pthread/thrd_sleep.c @@ -0,0 +1,36 @@ +/* C11 threads thread sleep implementation. + Copyright (C) 2018-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include <time.h> +#include <sysdep-cancel.h> + +#include "thrd_priv.h" + +int +thrd_sleep (const struct timespec* time_point, struct timespec* remaining) +{ + int ret = __clock_nanosleep (CLOCK_REALTIME, 0, time_point, remaining); + /* C11 states thrd_sleep function returns -1 if it has been interrupted + by a signal, or a negative value if it fails. */ + switch (ret) + { + case 0: return 0; + case EINTR: return -1; + default: return -2; + } +} diff --git a/sysdeps/pthread/threads.h b/sysdeps/pthread/threads.h new file mode 100644 index 0000000000..0ac489b4a1 --- /dev/null +++ b/sysdeps/pthread/threads.h @@ -0,0 +1,204 @@ +/* ISO C11 Standard: 7.26 - Thread support library <threads.h>. + Copyright (C) 2018-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#ifndef _THREADS_H +#define _THREADS_H 1 + +#include <features.h> +#include <time.h> + +__BEGIN_DECLS + +#include <bits/thread-shared-types.h> +#include <bits/types/struct_timespec.h> + +#ifndef __cplusplus +# define thread_local _Thread_local +#endif + +#define TSS_DTOR_ITERATIONS 4 +typedef __tss_t tss_t; +typedef void (*tss_dtor_t) (void*); + +typedef __thrd_t thrd_t; +typedef int (*thrd_start_t) (void*); + +/* Exit and error codes. */ +enum +{ + thrd_success = 0, + thrd_busy = 1, + thrd_error = 2, + thrd_nomem = 3, + thrd_timedout = 4 +}; + +/* Mutex types. */ +enum +{ + mtx_plain = 0, + mtx_recursive = 1, + mtx_timed = 2 +}; + +typedef __once_flag once_flag; +#define ONCE_FLAG_INIT __ONCE_FLAG_INIT + +typedef union +{ + char __size[__SIZEOF_PTHREAD_MUTEX_T]; + long int __align __LOCK_ALIGNMENT; +} mtx_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_COND_T]; + __extension__ long long int __align __LOCK_ALIGNMENT; +} cnd_t; + +/* Threads functions. */ + +/* Create a new thread executing the function __FUNC. Arguments for __FUNC + are passed through __ARG. If succesful, __THR is set to new thread + identifier. */ +extern int thrd_create (thrd_t *__thr, thrd_start_t __func, void *__arg); + +/* Check if __LHS and __RHS point to the same thread. */ +extern int thrd_equal (thrd_t __lhs, thrd_t __rhs); + +/* Return current thread identifier. */ +extern thrd_t thrd_current (void); + +/* Block current thread execution for at least the time pointed by + __TIME_POINT. The current thread may resume if receives a signal. In + that case, if __REMAINING is not NULL, the remaining time is stored in + the object pointed by it. */ +extern int thrd_sleep (const struct timespec *__time_point, + struct timespec *__remaining); + +/* Terminate current thread execution, cleaning up any thread local + storage and freeing resources. Returns the value specified in __RES. */ +extern void thrd_exit (int __res) __attribute__ ((__noreturn__)); + +/* Detach the thread identified by __THR from the current environment + (it does not allow join or wait for it). */ +extern int thrd_detach (thrd_t __thr); + +/* Block current thread until execution of __THR is complete. In case that + __RES is not NULL, will store the return value of __THR when exiting. */ +extern int thrd_join (thrd_t __thr, int *__res); + +/* Stop current thread execution and call the scheduler to decide which + thread should execute next. The current thread may be selected by the + scheduler to keep running. */ +extern void thrd_yield (void); + +#ifdef __USE_EXTERN_INLINES +/* Optimizations. */ +__extern_inline int +thrd_equal (thrd_t __thread1, thrd_t __thread2) +{ + return __thread1 == __thread2; +} +#endif + + +/* Mutex functions. */ + +/* Creates a new mutex object with type __TYPE. If successful the new + object is pointed by __MUTEX. */ +extern int mtx_init (mtx_t *__mutex, int __type); + +/* Block the current thread until the mutex pointed to by __MUTEX is + unlocked. In that case current thread will not be blocked. */ +extern int mtx_lock (mtx_t *__mutex); + +/* Block the current thread until the mutex pointed by __MUTEX is unlocked + or time pointed by __TIME_POINT is reached. In case the mutex is unlock, + the current thread will not be blocked. */ +extern int mtx_timedlock (mtx_t *__restrict __mutex, + const struct timespec *__restrict __time_point); + +/* Try to lock the mutex pointed by __MUTEX without blocking. If the mutex + is free the current threads takes control of it, otherwise it returns + immediately. */ +extern int mtx_trylock (mtx_t *__mutex); + +/* Unlock the mutex pointed by __MUTEX. It may potentially awake other + threads waiting on this mutex. */ +extern int mtx_unlock (mtx_t *__mutex); + +/* Destroy the mutex object pointed by __MUTEX. */ +extern void mtx_destroy (mtx_t *__mutex); + + +/* Call function __FUNC exactly once, even if invoked from several threads. + All calls must be made with the same __FLAGS object. */ +extern void call_once (once_flag *__flag, void (*__func)(void)); + + +/* Condition variable functions. */ + +/* Initialize new condition variable pointed by __COND. */ +extern int cnd_init (cnd_t *__cond); + +/* Unblock one thread that currently waits on condition variable pointed + by __COND. */ +extern int cnd_signal (cnd_t *__cond); + +/* Unblock all threads currently waiting on condition variable pointed by + __COND. */ +extern int cnd_broadcast (cnd_t *__cond); + +/* Block current thread on the condition variable pointed by __COND. */ +extern int cnd_wait (cnd_t *__cond, mtx_t *__mutex); + +/* Block current thread on the condition variable until condition variable + pointed by __COND is signaled or time pointed by __TIME_POINT is + reached. */ +extern int cnd_timedwait (cnd_t *__restrict __cond, + mtx_t *__restrict __mutex, + const struct timespec *__restrict __time_point); + +/* Destroy condition variable pointed by __cond and free all of its + resources. */ +extern void cnd_destroy (cnd_t *__COND); + + +/* Thread specific storage functions. */ + +/* Create new thread-specific storage key and stores it in the object pointed + by __TSS_ID. If __DESTRUCTOR is not NULL, the function will be called when + the thread terminates. */ +extern int tss_create (tss_t *__tss_id, tss_dtor_t __destructor); + +/* Return the value held in thread-specific storage for the current thread + identified by __TSS_ID. */ +extern void *tss_get (tss_t __tss_id); + +/* Sets the value of the thread-specific storage identified by __TSS_ID for + the current thread to __VAL. */ +extern int tss_set (tss_t __tss_id, void *__val); + +/* Destroys the thread-specific storage identified by __TSS_ID. The + destructor is not called until thrd_exit is called. */ +extern void tss_delete (tss_t __tss_id); + +__END_DECLS + +#endif /* _THREADS_H */ diff --git a/sysdeps/pthread/tss_create.c b/sysdeps/pthread/tss_create.c new file mode 100644 index 0000000000..4e170dd4fc --- /dev/null +++ b/sysdeps/pthread/tss_create.c @@ -0,0 +1,33 @@ +/* C11 threads thread-specific creation implementation. + Copyright (C) 2018-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include "thrd_priv.h" + +int +tss_create (tss_t *tss_id, tss_dtor_t destructor) +{ + _Static_assert (sizeof (tss_t) == sizeof (pthread_key_t), + "sizeof (tss_t) != sizeof (pthread_key_t)"); +#ifdef PTHREAD_DESTRUCTOR_ITERATIONS + _Static_assert (TSS_DTOR_ITERATIONS == PTHREAD_DESTRUCTOR_ITERATIONS, + "TSS_DTOR_ITERATIONS != PTHREAD_DESTRUCTOR_ITERATIONS"); +#endif + + int err_code = __pthread_key_create (tss_id, destructor); + return thrd_err_map (err_code); +} diff --git a/sysdeps/pthread/tss_delete.c b/sysdeps/pthread/tss_delete.c new file mode 100644 index 0000000000..38570ea100 --- /dev/null +++ b/sysdeps/pthread/tss_delete.c @@ -0,0 +1,25 @@ +/* C11 threads thread-specific delete implementation. + Copyright (C) 2018-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include "thrd_priv.h" + +void +tss_delete (tss_t tss_id) +{ + __pthread_key_delete (tss_id); +} diff --git a/sysdeps/pthread/tss_get.c b/sysdeps/pthread/tss_get.c new file mode 100644 index 0000000000..f8300b7b84 --- /dev/null +++ b/sysdeps/pthread/tss_get.c @@ -0,0 +1,25 @@ +/* C11 threads thread-specific get implementation. + Copyright (C) 2018-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include "thrd_priv.h" + +void * +tss_get (tss_t tss_id) +{ + return __pthread_getspecific (tss_id); +} diff --git a/sysdeps/pthread/tss_set.c b/sysdeps/pthread/tss_set.c new file mode 100644 index 0000000000..b21b6c2647 --- /dev/null +++ b/sysdeps/pthread/tss_set.c @@ -0,0 +1,26 @@ +/* C11 threads thread-specific set implementation. + Copyright (C) 2018-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include "thrd_priv.h" + +int +tss_set (tss_t tss_id, void *val) +{ + int err_code = __pthread_setspecific (tss_id, val); + return thrd_err_map (err_code); +} diff --git a/sysdeps/pthread/tst-call-once.c b/sysdeps/pthread/tst-call-once.c new file mode 100644 index 0000000000..c198233e8d --- /dev/null +++ b/sysdeps/pthread/tst-call-once.c @@ -0,0 +1,66 @@ +/* C11 threads call_once test. + Copyright (C) 2018-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include <threads.h> +#include <stdio.h> +#include <unistd.h> + +#include <support/check.h> + +/* Flag that controls the first thread access. */ +static once_flag flag = ONCE_FLAG_INIT; + +static int value = 0; + +static void +do_once (void) +{ + value++; +} + +static int +func (void* data) +{ + call_once (&flag, do_once); + thrd_exit (thrd_success); +} + +#define N 20 + +int +do_test (void) +{ + thrd_t ids[N]; + + for (int i = 0; i < N; ++i) + { + if (thrd_create (&ids[i], func, NULL) != thrd_success) + FAIL_EXIT1 ("thrd_create failed"); + } + + /* Join threads. */ + for (int i = 0; i < N; ++i) + { + if (thrd_join (ids[i], NULL) != thrd_success) + FAIL_EXIT1 ("thrd_join failed"); + } + + return (value != 1); +} + +#include <support/test-driver.c> diff --git a/sysdeps/pthread/tst-cnd-basic.c b/sysdeps/pthread/tst-cnd-basic.c new file mode 100644 index 0000000000..041762ae35 --- /dev/null +++ b/sysdeps/pthread/tst-cnd-basic.c @@ -0,0 +1,80 @@ +/* C11 threads condition variable tests. + Copyright (C) 2018-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include <threads.h> +#include <stdio.h> +#include <unistd.h> + +#include <support/check.h> + +/* Shared condition variable between child and parent. */ +static cnd_t cond; + +/* Mutex needed to signal and wait threads. */ +static mtx_t mutex; + +static int +signal_parent (void) +{ + /* Acquire the lock so that cnd_signal does not run until + cnd_timedwait has been called. */ + if (mtx_lock (&mutex) != thrd_success) + FAIL_EXIT1 ("mtx_lock failed"); + if (cnd_signal (&cond) != thrd_success) + FAIL_EXIT1 ("cnd_signal"); + if (mtx_unlock (&mutex) != thrd_success) + FAIL_EXIT1 ("mtx_unlock"); + + thrd_exit (thrd_success); +} + +static int +do_test (void) +{ + thrd_t id; + + if (cnd_init (&cond) != thrd_success) + FAIL_EXIT1 ("cnd_init failed"); + if (mtx_init (&mutex, mtx_plain) != thrd_success) + FAIL_EXIT1 ("mtx_init failed"); + + if (mtx_lock (&mutex) != thrd_success) + FAIL_EXIT1 ("mtx_lock failed"); + + if (thrd_create (&id, (thrd_start_t) signal_parent, NULL) + != thrd_success) + FAIL_EXIT1 ("thrd_create failed"); + + if (cnd_wait (&cond, &mutex) != thrd_success) + FAIL_EXIT1 ("cnd_wait failed"); + + /* Joining is not mandatory here, but still done to assure child thread + ends correctly. */ + if (thrd_join (id, NULL) != thrd_success) + FAIL_EXIT1 ("thrd_join failed"); + + if (mtx_unlock (&mutex) != thrd_success) + FAIL_EXIT1 ("mtx_unlock"); + + mtx_destroy (&mutex); + cnd_destroy (&cond); + + return 0; +} + +#include <support/test-driver.c> diff --git a/sysdeps/pthread/tst-cnd-broadcast.c b/sysdeps/pthread/tst-cnd-broadcast.c new file mode 100644 index 0000000000..ccc8504f6f --- /dev/null +++ b/sysdeps/pthread/tst-cnd-broadcast.c @@ -0,0 +1,97 @@ +/* C11 threads condition broadcast variable tests. + Copyright (C) 2018-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include <threads.h> +#include <stdbool.h> +#include <stdio.h> +#include <unistd.h> + +#include <support/check.h> + +/* Condition variable where child threads will wait. */ +static cnd_t cond; + +/* Mutex to control wait on cond. */ +static mtx_t mutex; + +/* Number of threads which have entered the cnd_wait region. */ +static unsigned int waiting_threads; + +/* Code executed by each thread. */ +static int +child_wait (void* data) +{ + /* Wait until parent thread sends broadcast here. */ + mtx_lock (&mutex); + ++waiting_threads; + cnd_wait (&cond, &mutex); + mtx_unlock (&mutex); + + thrd_exit (thrd_success); +} + +#define N 5 + +static int +do_test (void) +{ + thrd_t ids[N]; + unsigned char i; + + if (cnd_init (&cond) != thrd_success) + FAIL_EXIT1 ("cnd_init failed"); + if (mtx_init (&mutex, mtx_plain) != thrd_success) + FAIL_EXIT1 ("mtx_init failed"); + + /* Create N new threads. */ + for (i = 0; i < N; ++i) + { + if (thrd_create (&ids[i], child_wait, NULL) != thrd_success) + FAIL_EXIT1 ("thrd_create failed"); + } + + /* Wait for other threads to reach their wait func. */ + while (true) + { + mtx_lock (&mutex); + TEST_VERIFY (waiting_threads <= N); + bool done_waiting = waiting_threads == N; + mtx_unlock (&mutex); + if (done_waiting) + break; + thrd_sleep (&((struct timespec){.tv_nsec = 100 * 1000 * 1000}), NULL); + } + + mtx_lock (&mutex); + if (cnd_broadcast (&cond) != thrd_success) + FAIL_EXIT1 ("cnd_broadcast failed"); + mtx_unlock (&mutex); + + for (i = 0; i < N; ++i) + { + if (thrd_join (ids[i], NULL) != thrd_success) + FAIL_EXIT1 ("thrd_join failed"); + } + + mtx_destroy (&mutex); + cnd_destroy (&cond); + + return 0; +} + +#include <support/test-driver.c> diff --git a/sysdeps/pthread/tst-cnd-timedwait.c b/sysdeps/pthread/tst-cnd-timedwait.c new file mode 100644 index 0000000000..05e3a051a5 --- /dev/null +++ b/sysdeps/pthread/tst-cnd-timedwait.c @@ -0,0 +1,84 @@ +/* C11 threads condition timed wait variable tests. + Copyright (C) 2018-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include <threads.h> +#include <stdio.h> +#include <unistd.h> + +#include <support/check.h> + +/* Shared condition variable between child and parent. */ +static cnd_t cond; + +/* Mutex needed to signal and wait threads. */ +static mtx_t mutex; + +static int +signal_parent (void *arg) +{ + /* Acquire the lock so that cnd_signal does not run until + cnd_timedwait has been called. */ + if (mtx_lock (&mutex) != thrd_success) + FAIL_EXIT1 ("mtx_lock failed"); + if (cnd_signal (&cond) != thrd_success) + FAIL_EXIT1 ("cnd_signal failed"); + if (mtx_unlock (&mutex) != thrd_success) + FAIL_EXIT1 ("mtx_unlock"); + + thrd_exit (thrd_success); +} + +static int +do_test (void) +{ + thrd_t id; + struct timespec w_time; + + if (cnd_init (&cond) != thrd_success) + FAIL_EXIT1 ("cnd_init failed"); + if (mtx_init (&mutex, mtx_plain) != thrd_success) + FAIL_EXIT1 ("mtx_init failed"); + if (mtx_lock (&mutex) != thrd_success) + FAIL_EXIT1 ("mtx_lock failed"); + + if (clock_gettime (CLOCK_REALTIME, &w_time) != 0) + FAIL_EXIT1 ("clock_gettime failed"); + + /* This needs to be sufficiently long to prevent the cnd_timedwait + call from timing out. */ + w_time.tv_sec += 3600; + + if (thrd_create (&id, signal_parent, NULL) != thrd_success) + FAIL_EXIT1 ("thrd_create failed"); + + if (cnd_timedwait (&cond, &mutex, &w_time) != thrd_success) + FAIL_EXIT1 ("cnd_timedwait failed"); + + if (thrd_join (id, NULL) != thrd_success) + FAIL_EXIT1 ("thrd_join failed"); + + if (mtx_unlock (&mutex) != thrd_success) + FAIL_EXIT1 ("mtx_unlock"); + + mtx_destroy (&mutex); + cnd_destroy (&cond); + + return 0; +} + +#include <support/test-driver.c> diff --git a/sysdeps/pthread/tst-mtx-basic.c b/sysdeps/pthread/tst-mtx-basic.c new file mode 100644 index 0000000000..1e3d809bd0 --- /dev/null +++ b/sysdeps/pthread/tst-mtx-basic.c @@ -0,0 +1,73 @@ +/* C11 threads basic mutex tests. + Copyright (C) 2018-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include <threads.h> +#include <stdio.h> +#include <unistd.h> + +#include <support/check.h> + +/* Shared mutex between child and parent. */ +static mtx_t mutex; + +/* Shared counter to check possible race conditions. */ +static int counter; + +static int +child_add (void *arg) +{ + if (mtx_lock (&mutex) != thrd_success) + FAIL_EXIT1 ("mtx_lock failed"); + + counter++; + + if (mtx_unlock (&mutex) != thrd_success) + FAIL_EXIT1 ("mtx_unlock failed"); + + thrd_exit (thrd_success); +} + +static int +do_test (void) +{ + mtx_init (&mutex, mtx_plain); + + thrd_t id; + if (thrd_create (&id, child_add, NULL) != thrd_success) + FAIL_EXIT1 ("thrd_create failed"); + + if (mtx_lock (&mutex) != thrd_success) + FAIL_EXIT1 ("mtx_lock failed"); + + counter++; + + if (mtx_unlock (&mutex) != thrd_success) + FAIL_EXIT1 ("mtx_unlock failed"); + + if (thrd_join (id, NULL) != thrd_success) + FAIL_EXIT1 ("thrd_join failed"); + + if (counter != 2) + FAIL_EXIT1 ("counter (%d) != 2", counter); + + mtx_destroy (&mutex); + + return 0; +} + +#include <support/test-driver.c> diff --git a/sysdeps/pthread/tst-mtx-recursive.c b/sysdeps/pthread/tst-mtx-recursive.c new file mode 100644 index 0000000000..6b471ac724 --- /dev/null +++ b/sysdeps/pthread/tst-mtx-recursive.c @@ -0,0 +1,45 @@ +/* C11 threads recursive mutex tests. + Copyright (C) 2018-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include <threads.h> +#include <stdio.h> +#include <unistd.h> + +#include <support/check.h> + +static int +do_test (void) +{ + static mtx_t mutex; + + if (mtx_init (&mutex, mtx_recursive) != thrd_success) + FAIL_EXIT1 ("mtx_init failed"); + + if (mtx_lock (&mutex) != thrd_success) + FAIL_EXIT1 ("mtx_lock failed"); + + /* Lock mutex second time, if not recursive should deadlock. */ + if (mtx_lock (&mutex) != thrd_success) + FAIL_EXIT1 ("mtx_lock failed"); + + mtx_destroy (&mutex); + + return 0; +} + +#include <support/test-driver.c> diff --git a/sysdeps/pthread/tst-mtx-timedlock.c b/sysdeps/pthread/tst-mtx-timedlock.c new file mode 100644 index 0000000000..21c73a3d60 --- /dev/null +++ b/sysdeps/pthread/tst-mtx-timedlock.c @@ -0,0 +1,103 @@ +/* C11 threads timed mutex tests. + Copyright (C) 2018-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include <threads.h> +#include <stdio.h> +#include <unistd.h> + +#include <support/check.h> + +/* Shared mutex between child and parent. */ +static mtx_t mutex; + +/* Shared counter to check possible race conditions. */ +static char shrd_counter; + +/* Maximum amount of time waiting for mutex. */ +static struct timespec wait_time; + +/* Function to choose an action to do, depending on mtx_timedlock + return value. */ +static inline void +choose_action (int action, char* thread_name) +{ + switch (action) + { + case thrd_success: + ++shrd_counter; + + if (mtx_unlock (&mutex) != thrd_success) + FAIL_EXIT1 ("mtx_unlock failed"); + break; + + case thrd_timedout: + break; + + case thrd_error: + FAIL_EXIT1 ("%s lock error", thread_name); + break; + } +} + +static int +child_add (void *arg) +{ + char child_name[] = "child"; + + /* Try to lock mutex. */ + choose_action (mtx_timedlock (&mutex, &wait_time), child_name); + thrd_exit (thrd_success); +} + +static int +do_test (void) +{ + thrd_t id; + char parent_name[] = "parent"; + + if (mtx_init (&mutex, mtx_timed) != thrd_success) + FAIL_EXIT1 ("mtx_init failed"); + + if (clock_gettime (CLOCK_REALTIME, &wait_time) != 0) + FAIL_EXIT1 ("clock_gettime failed"); + /* Tiny amount of time, to assure that if any thread finds it busy. + It will receive thrd_timedout. */ + wait_time.tv_nsec += 1; + if (wait_time.tv_nsec == 1000 * 1000 * 1000) + { + wait_time.tv_sec += 1; + wait_time.tv_nsec = 0; + } + + if (thrd_create (&id, child_add, NULL) != thrd_success) + FAIL_EXIT1 ("thrd_create failed"); + + choose_action (mtx_timedlock (&mutex, &wait_time), parent_name); + + if (thrd_join (id, NULL) != thrd_success) + FAIL_EXIT1 ("thrd_join failed"); + + if (shrd_counter != 2 && shrd_counter != 1) + FAIL_EXIT1 ("shrd_counter != {1,2} (%d)", shrd_counter); + + mtx_destroy (&mutex); + + return 0; +} + +#include <support/test-driver.c> diff --git a/sysdeps/pthread/tst-mtx-trylock.c b/sysdeps/pthread/tst-mtx-trylock.c new file mode 100644 index 0000000000..dcb7a5407b --- /dev/null +++ b/sysdeps/pthread/tst-mtx-trylock.c @@ -0,0 +1,90 @@ +/* C11 threads trylock mutex tests. + Copyright (C) 2018-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include <threads.h> +#include <stdio.h> +#include <unistd.h> + +#include <support/check.h> + +/* Shared mutex between child and parent. */ +static mtx_t mutex; + +/* Shared counter to check possible race conditions. */ +static char shrd_counter; + +/* Function to choose an action to do, depending on mtx_trylock + return value. */ +static inline void +choose_action (int action, char* thread_name) +{ + switch (action) + { + case thrd_success: + ++shrd_counter; + + if (mtx_unlock (&mutex) != thrd_success) + FAIL_EXIT1 ("mtx_unlock failed"); + break; + + case thrd_busy: + break; + + case thrd_error: + FAIL_EXIT1 ("%s lock error", thread_name); + break; + } +} + +static int +child_add (void *arg) +{ + char child_name[] = "child"; + + /* Try to lock mutex. */ + choose_action (mtx_trylock (&mutex), child_name); + + thrd_exit (thrd_success); +} + +static int +do_test (void) +{ + thrd_t id; + char parent_name[] = "parent"; + + if (mtx_init (&mutex, mtx_timed) != thrd_success) + FAIL_EXIT1 ("mtx_init failed"); + + if (thrd_create (&id, child_add, NULL) != thrd_success) + FAIL_EXIT1 ("thrd_create failed"); + + choose_action (mtx_trylock (&mutex), parent_name); + + if (thrd_join (id, NULL) != thrd_success) + FAIL_EXIT1 ("thrd_join failed"); + + if (shrd_counter != 2 && shrd_counter != 1) + FAIL_EXIT1 ("shrd_counter != {1,2} (%d)", shrd_counter); + + mtx_destroy (&mutex); + + return 0; +} + +#include <support/test-driver.c> diff --git a/sysdeps/pthread/tst-thrd-detach.c b/sysdeps/pthread/tst-thrd-detach.c new file mode 100644 index 0000000000..53be296f97 --- /dev/null +++ b/sysdeps/pthread/tst-thrd-detach.c @@ -0,0 +1,52 @@ +/* C11 threads thread detach tests. + Copyright (C) 2018-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include <threads.h> +#include <time.h> +#include <stdio.h> +#include <unistd.h> + +#include <support/check.h> + +static int +detach_thrd (void *arg) +{ + if (thrd_detach (thrd_current ()) != thrd_success) + FAIL_EXIT1 ("thrd_detach failed"); + thrd_exit (thrd_success); +} + +static int +do_test (void) +{ + thrd_t id; + + /* Create new thread. */ + if (thrd_create (&id, detach_thrd, NULL) != thrd_success) + FAIL_EXIT1 ("thrd_create failed"); + + /* Give some time so the thread can finish. */ + thrd_sleep (&(struct timespec) {.tv_sec = 2}, NULL); + + if (thrd_join (id, NULL) == thrd_success) + FAIL_EXIT1 ("thrd_join succeed where it should fail"); + + return 0; +} + +#include <support/test-driver.c> diff --git a/sysdeps/pthread/tst-thrd-sleep.c b/sysdeps/pthread/tst-thrd-sleep.c new file mode 100644 index 0000000000..39d5fc7079 --- /dev/null +++ b/sysdeps/pthread/tst-thrd-sleep.c @@ -0,0 +1,51 @@ +/* C11 threads thread sleep tests. + Copyright (C) 2018-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include <threads.h> +#include <time.h> +#include <stdio.h> +#include <unistd.h> + +#include <support/check.h> + +static int +sleep_thrd (void *arg) +{ + struct timespec const *tl = (struct timespec const *) arg; + if (thrd_sleep (tl, NULL) != thrd_success) + FAIL_EXIT1 ("thrd_sleep failed"); + + thrd_exit (thrd_success); +} + +static int +do_test (void) +{ + thrd_t id; + struct timespec wait_time = {.tv_sec = 3}; + + if (thrd_create (&id, sleep_thrd, (void *) (&wait_time)) != thrd_success) + FAIL_EXIT1 ("thrd_create failed"); + + if (thrd_join (id, NULL) != thrd_success) + FAIL_EXIT1 ("thrd failed"); + + return 0; +} + +#include <support/test-driver.c> diff --git a/sysdeps/pthread/tst-tss-basic.c b/sysdeps/pthread/tst-tss-basic.c new file mode 100644 index 0000000000..3b06abc5cf --- /dev/null +++ b/sysdeps/pthread/tst-tss-basic.c @@ -0,0 +1,75 @@ +/* C11 threads specific storage tests. + Copyright (C) 2018-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include <threads.h> +#include <stdio.h> +#include <unistd.h> + +#include <support/check.h> + +/* Thread specific storage. */ +static tss_t key; + +#define TSS_VALUE (void*) 0xFF + +static int +tss_thrd (void *arg) +{ + if (tss_create (&key, NULL) != thrd_success) + FAIL_EXIT1 ("tss_create failed"); + + if (tss_set (key, TSS_VALUE)) + FAIL_EXIT1 ("tss_set failed"); + + void *value = tss_get (key); + if (value == 0) + FAIL_EXIT1 ("tss_get failed"); + if (value != TSS_VALUE) + FAIL_EXIT1 ("tss_get returned %p, expected %p", value, TSS_VALUE); + + thrd_exit (thrd_success); +} + +static int +do_test (void) +{ + /* Setting an invalid key should return an error. */ + if (tss_set (key, TSS_VALUE) == thrd_success) + FAIL_EXIT1 ("tss_set succeed where it should have failed"); + + if (tss_create (&key, NULL) != thrd_success) + FAIL_EXIT1 ("tss_create failed"); + + thrd_t id; + if (thrd_create (&id, tss_thrd, NULL) != thrd_success) + FAIL_EXIT1 ("thrd_create failed"); + + if (thrd_join (id, NULL) != thrd_success) + FAIL_EXIT1 ("thrd failed"); + + /* The value set in tss_thrd should not be visible here. */ + void *value = tss_get (key); + if (value != 0) + FAIL_EXIT1 ("tss_get succeed where it should have failed"); + + tss_delete (key); + + return 0; +} + +#include <support/test-driver.c> |