-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathsem.go
163 lines (143 loc) · 3.95 KB
/
sem.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
// Project: C1515
// Author: Michael John
// Copyright: 2014-2018 Crown Equipment Corp.
// +build linux,cgo
// Package semaphore provides an interface to named userspace semaphores.
package semaphore
import (
"errors"
"syscall"
"time"
"unsafe"
)
// #cgo LDFLAGS: -pthread
// #include <stdlib.h>
// #include <fcntl.h>
// #include <sys/stat.h>
// #include <sys/types.h>
// #include <semaphore.h>
// #include <time.h>
// #ifndef GO_SEM_LIB_
// #define GO_SEM_LIB_
// sem_t* Go_sem_open(const char *name, int oflag, mode_t mode, unsigned int value)
// {
// return sem_open(name, oflag, mode, value);
// }
// #endif
import "C"
type Semaphore struct {
sem *C.sem_t //semaphore returned by sem_open
name string //name of semaphore
}
func (s *Semaphore) isSemaphoreInitialized() (bool, error) {
if s.sem == nil {
return false, errors.New("Not a valid semaphore")
}
return true, nil
}
// Open creates a new POSIX semaphore or opens an existing semaphore.
// The semaphore is identified by name. The mode argument specifies the permissions
// to be placed on the new semaphore. The value argument specifies the initial
// value for the new semaphore. If the named semaphore already exist, mode and
// value are ignored.
// For details see sem_overview(7).
func (s *Semaphore) Open(name string, mode, value uint32) error {
s.name = name
n := C.CString(name)
var err error
s.sem, err = C.Go_sem_open(n, syscall.O_CREAT, C.mode_t(mode), C.uint(value))
C.free(unsafe.Pointer(n))
if s.sem == nil {
return err
}
return nil
}
// Close closes the named semaphore, allowing any resources that the system has
// allocated to the calling process for this semaphore to be freed.
func (s *Semaphore) Close() error {
if ok, err := s.isSemaphoreInitialized(); !ok {
return err
}
ret, err := C.sem_close(s.sem)
if ret != 0 {
return err
}
s.sem = nil
return nil
}
// GetValue returns the current value of the semaphore.
func (s *Semaphore) GetValue() (int, error) {
if ok, err := s.isSemaphoreInitialized(); !ok {
return 0, err
}
var val C.int
ret, err := C.sem_getvalue(s.sem, &val)
if ret != 0 {
return int(ret), err
}
return int(val), nil
}
// Post increments the semaphore.
func (s *Semaphore) Post() error {
if ok, err := s.isSemaphoreInitialized(); !ok {
return err
}
ret, err := C.sem_post(s.sem)
if ret != 0 {
return err
}
return nil
}
// Wait decrements the semaphore. 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, or a signal interrupts the call.
func (s *Semaphore) Wait() error {
if ok, err := s.isSemaphoreInitialized(); !ok {
return err
}
ret, err := C.sem_wait(s.sem)
if ret != 0 {
return err
}
return nil
}
// TryWait is the same as Wait(), except that if the decrement cannot be immediately
// performed, then the call returns an error instead of blocking.
func (s *Semaphore) TryWait() error {
if ok, err := s.isSemaphoreInitialized(); !ok {
return err
}
ret, err := C.sem_trywait(s.sem)
if ret != 0 {
return err
}
return nil
}
// TimedWait is the same as Wait(), except that d specifies a limit on the
// amount of time that the call should block if the decrement cannot be
// immediately performed.
func (s *Semaphore) TimedWait(d time.Duration) error {
if err := s.TryWait(); err == nil {
// success
return nil
}
time.Sleep(d)
if err := s.TryWait(); err == nil {
// success
return nil
}
return errors.New("The call timed out before the semaphore could be locked")
}
// Unlink removes the named semaphore. The semaphore name is removed immediately.
// The semaphore is destroyed once all other processes that have the semaphore
// open close it.
func (s *Semaphore) Unlink() error {
name := C.CString(s.name)
ret, err := C.sem_unlink(name)
C.free(unsafe.Pointer(name))
if ret != 0 {
return err
}
return nil
}