Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@akutz
Created April 25, 2016 16:32
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save akutz/61e00506f95a9219f9068d438f1f59c4 to your computer and use it in GitHub Desktop.
Save akutz/61e00506f95a9219f9068d438f1f59c4 to your computer and use it in GitHub Desktop.
Golang Semaphores
package semaphore
import (
"time"
)
// Semaphore enables processes and threads to synchronize their actions.
type Semaphore interface {
// Close closes the semaphore.
Close() error
// Unlock increments (unlocks) the semaphore pointed to by sem. If
// the semaphore's value consequently becomes greater than zero, then
// another process or thread blocked in a Wait() call will be woken
// up and proceed to lock the semaphore.
Unlock() error
// Wait decrements (locks) the semaphore pointed to by sem. If
// the semaphore's value is greater than zero, then the decrement
// proceeds, and the function returns, immediately. If the semaphore
// currently has the value zero, then the call blocks until either it
// becomes possible to perform the decrement (i.e., the semaphore value
// ises above zero), or a signal handler interrupts the call.
Wait() error
// TryWait is the same as Wait(), except that if the decrement
// cannot be immediately performed, then call returns an error (errno
// set to C.EAGAIN) instead of blocking.
TryWait() error
// TimedWait is the same as Wait(), except that abs_timeout
// specifies a limit on the amount of time that the call should block if
// the decrement cannot be immediately performed.
TimedWait(timeout *time.Time) error
// Value returns the current value of the semaphore. If one or more
// processes or threads are blocked waiting to lock the
// semaphore with Wait(), POSIX.1 permits two possibilities for the
// value returned in sval: either 0 is returned; or a negative number
// whose absolute value is the count of the number of processes and
// threads currently blocked in Wait(). Linux adopts the former
// behavior.
Value() (int, error)
}
// Open creates a new, named semaphore or opens an existing one if one exists
// with the given name.
func Open(name string, excl bool) (Semaphore, error) {
return open(name, excl)
}
package semaphore
import (
"time"
"github.com/akutz/goof"
)
func (s *semaphore) timedWait(t *time.Time) error {
return goof.New("unsupported")
}
func (s *semaphore) value() (int, error) {
return -1, goof.New("unsupported")
}
// +build darwin
package semaphore
// #include <fcntl.h> /* For O_* constants */
// #include <sys/stat.h> /* For mode constants */
// #include <semaphore.h>
// #include <string.h>
// #include <stdlib.h>
// #include <errno.h>
// #include <stdio.h>
/*
int _errno() {
return errno;
}
typedef struct {
sem_t* val;
int err;
} sem_tt;
sem_tt* _sem_open(char* name, int flags) {
sem_tt* r = (sem_tt*)malloc(sizeof(sem_tt));
sem_t* sem = sem_open((const char*)name, flags, 0644, 0);
if (sem == SEM_FAILED) r->err = errno;
else r->val = sem;
return r;
}
int _sem_close(void* sem) {
return sem_close(((sem_tt*)sem)->val) == 0 ? 0 : errno;
}
int _sem_wait(void* sem) {
return sem_wait(((sem_tt*)sem)->val) == 0 ? 0 : errno;
}
int _sem_trywait(void* sem) {
return sem_trywait(((sem_tt*)sem)->val) == 0 ? 0 : errno;
}
int _sem_post(void* sem) {
return sem_post(((sem_tt*)sem)->val) == 0 ? 0 : errno;
}
int _sem_unlink(char* name) {
return sem_unlink((const char*) name) == 0 ? 0 : errno;
}
int* pInt() {
int* val = (int*)malloc(sizeof(int));
return val;
}
const char* cpchar(char* val) {
return (const char*)val;
}
const struct timespec* new_timespec(time_t sec, long nsec) {
struct timespec* val = (struct timespec*)malloc(sizeof(struct timespec));
val->tv_sec = sec;
val->tv_nsec = nsec;
return (const struct timespec*)val;
}
*/
import "C"
import (
"fmt"
"time"
"unsafe"
"github.com/akutz/goof"
)
type semaphore struct {
name string
cName *C.char
sema unsafe.Pointer
}
func open(name string, excl bool) (Semaphore, error) {
name = fmt.Sprintf("/%s", name)
cName := C.CString(name)
flags := C.O_CREAT
if excl {
flags = flags | C.O_EXCL
}
sema := C._sem_open(cName, C.int(flags))
if sema.err != 0 {
return nil, goof.WithFields(goof.Fields{
"name": name,
"error": sema.err,
}, "error opening semaphore")
}
return &semaphore{
name: name,
cName: cName,
sema: unsafe.Pointer(sema),
}, nil
}
func (s *semaphore) Close() error {
err := C._sem_close(s.sema)
if err == 0 {
return nil
}
return goof.WithFields(goof.Fields{
"name": s.name,
"error": int(err),
}, "error closing semaphore")
}
func (s *semaphore) Unlock() error {
err := C._sem_post(s.sema)
if err == 0 {
return nil
}
return goof.WithFields(goof.Fields{
"name": s.name,
"error": int(err),
}, "error unlocking semaphore")
}
func (s *semaphore) Value() (int, error) {
return s.value()
}
func (s *semaphore) Wait() error {
err := C._sem_wait(s.sema)
if err == 0 {
return nil
}
return goof.WithFields(goof.Fields{
"name": s.name,
"error": int(err),
}, "error waiting on semaphore")
}
func (s *semaphore) TryWait() error {
err := C._sem_trywait(s.sema)
if err == 0 || err == C.EAGAIN {
return nil
}
return goof.WithFields(goof.Fields{
"name": s.name,
"error": int(err),
}, "error trying wait on semaphore")
}
func (s *semaphore) TimedWait(t *time.Time) error {
return s.timedWait(t)
}
func Unlink(name string) error {
name = fmt.Sprintf("/%s", name)
cName := C.CString(name)
err := C._sem_unlink(cName)
if err == 0 {
return nil
}
return goof.WithFields(goof.Fields{
"name": name,
"error": int(err),
}, "error unlinking semaphore")
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment