Created
April 25, 2016 16:32
-
-
Save akutz/61e00506f95a9219f9068d438f1f59c4 to your computer and use it in GitHub Desktop.
Golang Semaphores
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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") | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// +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