diff --git a/libc/include/unistd.h b/libc/include/unistd.h index 73291194..6a97b01a 100644 --- a/libc/include/unistd.h +++ b/libc/include/unistd.h @@ -96,8 +96,7 @@ __BEGIN_DECLS TODO: Uncomment when regular expressions are implemented. */ /* #define _POSIX_SAVED_IDS 1 TODO: Uncomment when saved ids are implemented. I forgot if they already are. */ -/* #define _POSIX_SEMAPHORES 200809L - TODO: Uncomment when named semaphores are implemented. */ +#define _POSIX_SEMAPHORES 200809L /*TODO: _POSIX_SHARED_MEMORY_OBJECTS - Research what this is. */ #define _POSIX_SHELL 1 /*TODO: _POSIX_SPAWN - Research what this is. */ diff --git a/libpthread/Makefile b/libpthread/Makefile index e0e32a91..78ec4c6d 100644 --- a/libpthread/Makefile +++ b/libpthread/Makefile @@ -56,6 +56,13 @@ pthread_rwlock_wrlock.o \ pthread_self.o \ pthread_setspecific.o \ pthread_sigmask.o \ +sem_destroy.o \ +sem_getvalue.o \ +sem_init.o \ +sem_post.o \ +sem_timedwait.o \ +sem_trywait.o \ +sem_wait.o \ BINS:=libpthread.a diff --git a/libpthread/include/semaphore.h b/libpthread/include/semaphore.h new file mode 100644 index 00000000..1578bfac --- /dev/null +++ b/libpthread/include/semaphore.h @@ -0,0 +1,58 @@ +/******************************************************************************* + + Copyright(C) Jonas 'Sortie' Termansen 2014. + + This file is part of Sortix libpthread. + + Sortix libpthread 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 3 of the License, or (at your + option) any later version. + + Sortix libpthread 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 Sortix libpthread. If not, see . + + semaphore.h + Semaphore API. + +*******************************************************************************/ + +#ifndef INCLUDE_SEMAPHORE_H +#define INCLUDE_SEMAPHORE_H + +#include + +#include + +__BEGIN_DECLS + +typedef struct +{ +#if defined(__is_sortix_libpthread) + int value; +#else + int __value; +#endif +} sem_t; + +#define SEM_FAILED ((sem_t*) 0) + +/*int sem_close(sem_t*);*/ +int sem_destroy(sem_t*); +int sem_getvalue(sem_t* __restrict, int* __restrict); +int sem_init(sem_t*, int, unsigned int); +/*sem_t* sem_open(const char*, int, ...);*/ +int sem_post(sem_t*); +int sem_timedwait(sem_t* __restrict, const struct timespec* __restrict); +int sem_trywait(sem_t*); +/*int sem_unlink(const char*);*/ +int sem_wait(sem_t*); + +__END_DECLS + +#endif diff --git a/libpthread/sem_destroy.c++ b/libpthread/sem_destroy.c++ new file mode 100644 index 00000000..9cfc9634 --- /dev/null +++ b/libpthread/sem_destroy.c++ @@ -0,0 +1,31 @@ +/******************************************************************************* + + Copyright(C) Jonas 'Sortie' Termansen 2014. + + This file is part of Sortix libpthread. + + Sortix libpthread 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 3 of the License, or (at your + option) any later version. + + Sortix libpthread 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 Sortix libpthread. If not, see . + + sem_destroy.c++ + Destroy a semaphore. + +*******************************************************************************/ + +#include + +extern "C" int sem_destroy(sem_t* sem) +{ + (void) sem; + return 0; +} diff --git a/libpthread/sem_getvalue.c++ b/libpthread/sem_getvalue.c++ new file mode 100644 index 00000000..6f37d5d2 --- /dev/null +++ b/libpthread/sem_getvalue.c++ @@ -0,0 +1,31 @@ +/******************************************************************************* + + Copyright(C) Jonas 'Sortie' Termansen 2014. + + This file is part of Sortix libpthread. + + Sortix libpthread 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 3 of the License, or (at your + option) any later version. + + Sortix libpthread 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 Sortix libpthread. If not, see . + + sem_getvalue.c++ + Get the value of a semaphore. + +*******************************************************************************/ + +#include + +extern "C" int sem_getvalue(sem_t* restrict sem, int* restrict value_ptr) +{ + *value_ptr = __atomic_load_n(&sem->value, __ATOMIC_SEQ_CST); + return 0; +} diff --git a/libpthread/sem_init.c++ b/libpthread/sem_init.c++ new file mode 100644 index 00000000..e25d3983 --- /dev/null +++ b/libpthread/sem_init.c++ @@ -0,0 +1,40 @@ +/******************************************************************************* + + Copyright(C) Jonas 'Sortie' Termansen 2014. + + This file is part of Sortix libpthread. + + Sortix libpthread 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 3 of the License, or (at your + option) any later version. + + Sortix libpthread 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 Sortix libpthread. If not, see . + + sem_init.c++ + Initialize a semaphore. + +*******************************************************************************/ + +#include +#include +#include + +extern "C" int sem_init(sem_t* sem, int pshared, unsigned int value) +{ + if ( pshared ) + return errno = ENOSYS, -1; + + if ( (unsigned int) INT_MAX < value ) + return errno = EINVAL, -1; + + sem->value = (int) value; + + return 0; +} diff --git a/libpthread/sem_post.c++ b/libpthread/sem_post.c++ new file mode 100644 index 00000000..2d3fc302 --- /dev/null +++ b/libpthread/sem_post.c++ @@ -0,0 +1,45 @@ +/******************************************************************************* + + Copyright(C) Jonas 'Sortie' Termansen 2014. + + This file is part of Sortix libpthread. + + Sortix libpthread 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 3 of the License, or (at your + option) any later version. + + Sortix libpthread 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 Sortix libpthread. If not, see . + + sem_post.c++ + Unlock a semaphore. + +*******************************************************************************/ + +#include +#include +#include + +extern "C" int sem_post(sem_t* sem) +{ + while ( true ) + { + int old_value = __atomic_load_n(&sem->value, __ATOMIC_SEQ_CST); + if ( old_value == INT_MAX ) + return errno = EOVERFLOW; + + int new_value = old_value + 1; + if ( !__atomic_compare_exchange_n(&sem->value, &old_value, new_value, + false, + __ATOMIC_SEQ_CST, __ATOMIC_RELAXED) ) + continue; + + return 0; + } +} diff --git a/libpthread/sem_timedwait.c++ b/libpthread/sem_timedwait.c++ new file mode 100644 index 00000000..dda967c9 --- /dev/null +++ b/libpthread/sem_timedwait.c++ @@ -0,0 +1,76 @@ +/******************************************************************************* + + Copyright(C) Jonas 'Sortie' Termansen 2014. + + This file is part of Sortix libpthread. + + Sortix libpthread 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 3 of the License, or (at your + option) any later version. + + Sortix libpthread 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 Sortix libpthread. If not, see . + + sem_timedwait.c++ + Lock a semaphore. + +*******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +extern "C" +int sem_timedwait(sem_t* restrict sem, const struct timespec* restrict abstime) +{ + if ( sem_trywait(sem) == 0 ) + return 0; + if ( errno != EAGAIN ) + return -1; + + sigset_t old_set_mask; + sigset_t old_set_allowed; + sigset_t all_signals; + sigfillset(&all_signals); + sigprocmask(SIG_SETMASK, &all_signals, &old_set_mask); + signotset(&old_set_allowed, &old_set_mask); + + while ( sem_trywait(sem) != 0 ) + { + // TODO: Using CLOCK_REALTIME for this is bad as it is not monotonic. We + // need to enchance the semaphore API so a better clock can be + // used instead. + if ( errno == EAGAIN ) + { + struct timespec now; + clock_gettime(CLOCK_REALTIME, &now); + if ( timespec_le(*abstime, now) ) + errno = ETIMEDOUT; + } + + if ( errno == EAGAIN && sigpending(&old_set_allowed) ) + errno = EINTR; + + if ( errno != EAGAIN ) + { + sigprocmask(SIG_SETMASK, &old_set_mask, NULL); + return -1; + } + + sched_yield(); + } + + sigprocmask(SIG_SETMASK, &old_set_mask, NULL); + + return 0; +} diff --git a/libpthread/sem_trywait.c++ b/libpthread/sem_trywait.c++ new file mode 100644 index 00000000..b247d0e4 --- /dev/null +++ b/libpthread/sem_trywait.c++ @@ -0,0 +1,38 @@ +/******************************************************************************* + + Copyright(C) Jonas 'Sortie' Termansen 2014. + + This file is part of Sortix libpthread. + + Sortix libpthread 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 3 of the License, or (at your + option) any later version. + + Sortix libpthread 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 Sortix libpthread. If not, see . + + sem_trywait.c++ + Lock a semaphore. + +*******************************************************************************/ + +#include +#include + +extern "C" int sem_trywait(sem_t* sem) +{ + int old_value = __atomic_load_n(&sem->value, __ATOMIC_SEQ_CST); + if ( old_value <= 0 ) + return errno = EAGAIN, -1; + int new_value = old_value - 1; + if ( !__atomic_compare_exchange_n(&sem->value, &old_value, new_value, false, + __ATOMIC_SEQ_CST, __ATOMIC_RELAXED) ) + return errno = EAGAIN, -1; + return 0; +} diff --git a/libpthread/sem_wait.c++ b/libpthread/sem_wait.c++ new file mode 100644 index 00000000..3de9ecf1 --- /dev/null +++ b/libpthread/sem_wait.c++ @@ -0,0 +1,62 @@ +/******************************************************************************* + + Copyright(C) Jonas 'Sortie' Termansen 2014. + + This file is part of Sortix libpthread. + + Sortix libpthread 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 3 of the License, or (at your + option) any later version. + + Sortix libpthread 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 Sortix libpthread. If not, see . + + sem_wait.c++ + Lock a semaphore. + +*******************************************************************************/ + +#include +#include +#include +#include +#include + +extern "C" int sem_wait(sem_t* sem) +{ + if ( sem_trywait(sem) == 0 ) + return 0; + if ( errno != EAGAIN ) + return -1; + + sigset_t old_set_mask; + sigset_t old_set_allowed; + sigset_t all_signals; + sigfillset(&all_signals); + sigprocmask(SIG_SETMASK, &all_signals, &old_set_mask); + signotset(&old_set_allowed, &old_set_mask); + + while ( sem_trywait(sem) != 0 ) + { + if ( errno == EAGAIN && sigpending(&old_set_allowed) ) + errno = EINTR; + + if ( errno != EAGAIN ) + { + sigprocmask(SIG_SETMASK, &old_set_mask, NULL); + return -1; + } + + sched_yield(); + } + + sigprocmask(SIG_SETMASK, &old_set_mask, NULL); + + return 0; +}