[COMMIT osv master] Added POSIX named semaphore implementation

1 view
Skip to first unread message

Commit Bot

unread,
Sep 10, 2023, 6:18:16 AM9/10/23
to osv...@googlegroups.com, Landon Johnson
From: Landon Johnson <lan...@cs.utexas.edu>
Committer: Nadav Har'El <n...@scylladb.com>
Branch: master

Added POSIX named semaphore implementation

Signed-off-by: Landon Johnson <lan...@cs.utexas.edu>

Closes #1232

---
diff --git a/libc/sem.cc b/libc/sem.cc
--- a/libc/sem.cc
+++ b/libc/sem.cc
@@ -6,18 +6,46 @@
*/

#include <semaphore.h>
+#include <fcntl.h>
#include <osv/semaphore.hh>
#include <osv/sched.hh>
#include <memory>
#include "libc.hh"
+#include <unordered_map>

// FIXME: smp safety

-struct indirect_semaphore : std::unique_ptr<semaphore> {
- explicit indirect_semaphore(unsigned units)
- : std::unique_ptr<semaphore>(new semaphore(units)) {}
+struct posix_semaphore : semaphore {
+ private:
+ int references;
+ bool named;
+ public:
+ posix_semaphore(int units, int refs, bool named)
+ : semaphore(units), references(refs), named(named) {}
+
+ void add_reference(){
+ references++;
+ }
+
+ void remove_reference(){
+ references--;
+ }
+
+ bool not_referenced(){
+ return references <= 0;
+ }
+
+ void unlink(){
+ named = false;
+ }
+
+ bool linked(){
+ return named;
+ }
};

+using indirect_semaphore = std::unique_ptr<posix_semaphore>;
+
indirect_semaphore& from_libc(sem_t* p)
{
return *reinterpret_cast<indirect_semaphore*>(p);
@@ -27,7 +55,8 @@ OSV_LIBC_API
int sem_init(sem_t* s, int pshared, unsigned val)
{
static_assert(sizeof(indirect_semaphore) <= sizeof(*s), "sem_t overflow");
- new (s) indirect_semaphore(val);
+ posix_semaphore *sem = new posix_semaphore(val, 1, false);
+ new (s) indirect_semaphore(sem);
return 0;
}

@@ -76,3 +105,67 @@ int sem_trywait(sem_t* s)
return libc_error(EAGAIN);
return 0;
}
+
+static std::unordered_map<std::string, indirect_semaphore> named_semaphores;
+static mutex named_semaphores_mutex;
+
+OSV_LIBC_API
+sem_t *sem_open(const char *name, int oflag, mode_t mode, unsigned int value)
+{
+ SCOPE_LOCK(named_semaphores_mutex);
+ auto iter = named_semaphores.find(std::string(name));
+
+ if (iter != named_semaphores.end()) {
+ //opening already named semaphore
+ if (oflag & O_EXCL && oflag & O_CREAT) {
+ errno = EEXIST;
+ return SEM_FAILED;
+ }
+
+ iter->second->add_reference();
+ return reinterpret_cast<sem_t*>(&(iter->second));
+ }
+ else if (oflag & O_CREAT) {
+ //creating new semaphore
+ if (value > SEM_VALUE_MAX) {
+ errno = EINVAL;
+ return SEM_FAILED;
+ }
+
+ named_semaphores.emplace(std::string(name), std::make_unique<posix_semaphore>(value, 1, true));
+ return reinterpret_cast<sem_t *>(&named_semaphores[std::string(name)]);
+ }
+
+ errno = ENOENT;
+ return SEM_FAILED;
+}
+
+OSV_LIBC_API
+int sem_unlink(const char *name)
+{
+ SCOPE_LOCK(named_semaphores_mutex);
+ auto iter = named_semaphores.find(std::string(name));
+ if (iter != named_semaphores.end()) {
+ iter->second->unlink();
+ if (iter->second->not_referenced()) {
+ sem_destroy(reinterpret_cast<sem_t *>(&iter->second));
+ }
+ named_semaphores.erase(iter);
+ return 0;
+ }
+
+ errno = ENOENT;
+ return -1;
+}
+
+OSV_LIBC_API
+int sem_close(sem_t *sem)
+{
+ SCOPE_LOCK(named_semaphores_mutex);
+ indirect_semaphore &named_sem = from_libc(sem);
+ named_sem->remove_reference();
+ if (!named_sem->linked() && named_sem->not_referenced()) {
+ sem_destroy(sem);
+ }
+ return 0;
+}
\ No newline at end of file
diff --git a/tests/tst-semaphore.c b/tests/tst-semaphore.c
--- a/tests/tst-semaphore.c
+++ b/tests/tst-semaphore.c
@@ -11,6 +11,7 @@
#include <unistd.h>
#include <semaphore.h>
#include <assert.h>
+#include <fcntl.h>

#define THREAD_NUMBER 10

@@ -55,5 +56,46 @@ int main(void) {
assert(sem_destroy(&sem_sync) == 0);
assert(sem_destroy(&sem_done) == 0);

+ ///Named sempahore test
+
+ //Create and open two handles to a named semaphore
+ sem_t *named_sem1 = sem_open("name", O_CREAT, 0777, 1);
+ assert(named_sem1 != SEM_FAILED);
+ sem_t *named_sem2 = sem_open("name", O_EXCL, 0, 0);
+ assert(named_sem1 == named_sem2);
+
+ //Can't create a new named semaphore without O_CREAT
+ assert(sem_open("other", 0, 0777, 1) == SEM_FAILED);
+ assert(sem_open("other", O_EXCL | O_SYNC, 0777, 1) == SEM_FAILED);
+
+ //Any other flags should have no effect if the named semaphore does not exist
+ sem_t *named_sem3 = sem_open("other", O_EXCL | O_CREAT | O_SYNC, 0777, 1);
+ assert(named_sem3 != SEM_FAILED);
+ assert(sem_unlink("other") == 0);
+ assert(sem_close(named_sem3) == 0);
+
+ //Close both handles to the semaphore without removing the name
+ assert(sem_close(named_sem1) == 0);
+ assert(sem_close(named_sem2) == 0);
+
+ //Open two more handles to the named sempahore
+ named_sem1 = sem_open("name", 0);
+ assert(named_sem1 != SEM_FAILED);
+ named_sem2 = sem_open("name", 0);
+ assert(named_sem1 == named_sem2);
+
+ //Can't open existing semaphore with O_CREAT and O_EXCL set
+ assert(sem_open("name", O_CREAT | O_EXCL, 0777, 1) == SEM_FAILED);
+ assert(sem_open("name", O_CREAT | O_EXCL | O_SYNC, 0777, 1) == SEM_FAILED);
+
+ //Unlink the named semaphore. Can't open more handles.
+ assert(sem_unlink("name") == 0);
+ assert(sem_unlink("name") == -1);
+ assert(sem_open("name", 0) == SEM_FAILED);
+
+ //Close handles
+ assert(sem_close(named_sem1) == 0);
+ assert(sem_close(named_sem2) == 0);
+
return 0;
}
Reply all
Reply to author
Forward
0 new messages