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;
+}