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; } -- You received this message because you are subscribed to the Google Groups "OSv Development" group. To unsubscribe from this group and stop receiving emails from it, send an email to osv-dev+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/osv-dev/0000000000001eb0170604fe87ef%40google.com.