-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpsem.c
More file actions
143 lines (118 loc) · 2.54 KB
/
psem.c
File metadata and controls
143 lines (118 loc) · 2.54 KB
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
/**
* An implementation of posix semaphores using sysv semaphores.
*/
#include <unistd.h>
#include <stdlib.h>
#include <sys/sem.h>
#include <sys/stat.h>
#include <stdio.h>
#include <limits.h>
#include <fcntl.h>
#define SEM_FAILED 0
typedef struct _sem {
int id;
char *path;
} sem_t;
union semun {
int val;
struct semid_ds *buf;
unsigned short *array;
#if defined(__linux__)
struct seminfo *__buf;
#endif
};
int sem_post(sem_t *sem) {
struct sembuf sop;
sop.sem_num = 0;
sop.sem_op = 1;
sop.sem_flg = 0;
return semop(sem->id, &sop, 1);
}
int sem_wait(sem_t *sem) {
struct sembuf sop;
sop.sem_num = 0;
sop.sem_op = -1;
sop.sem_flg = 0;
return semop(sem->id, &sop, 1);
}
int sem_init(sem_t *sem, int pshared, unsigned int value) {
int id;
union semun arg;
arg.val = value;
id = semget(IPC_PRIVATE, 1, IPC_CREAT | S_IRWXU | S_IRWXO | S_IRWXG);
if (id == -1)
return -1;
if (semctl(id, 0, SETVAL, arg) == -1)
return -1;
sem->id = id;
sem->path = NULL;
return 0;
}
sem_t *sem_open(const char *name, int oflag, mode_t mode, unsigned int value) {
int fd;
sem_t *sem;
union semun arg;
if ((sem->path = malloc(PATH_MAX)) == NULL)
return (sem_t*)SEM_FAILED;
if (snprintf(sem->path, PATH_MAX, "/tmp/sem_%s", name) < 0)
return (sem_t*)SEM_FAILED;
// This should hand'e all the O_EXCL/CREAT details
if ((fd = open(sem->path, oflag)) == -1)
return (sem_t*)SEM_FAILED;
if (close(fd) == -1)
return (sem_t*)SEM_FAILED;
if ((sem->id = semget(ftok(sem->path, 1), 1, IPC_CREAT | oflag)) == -1)
return (sem_t*)SEM_FAILED;
arg.val = value;
if (semctl(sem->id, 0, SETVAL, arg) == -1)
return (sem_t*)SEM_FAILED;
return sem;
}
int sem_close(sem_t *sem) {
free(sem);
return 0;
}
int sem_unlink(sem_t *sem) {
union semun arg;
if (unlink(sem->path) == -1)
return -1;
if (semctl(sem->id, 0, IPC_RMID, arg) == -1)
return -1;
return 0;
}
int sem_destroy(sem_t *sem) {
union semun arg;
return semctl(sem->id, 0, IPC_RMID, arg);
}
// Test the above
static void exit_err(char *reason) {
perror(reason);
exit(EXIT_FAILURE);
}
int main(int argc, char **argv) {
sem_t sem;
puts("init value 1");
if (sem_init(&sem, 0, 1) == -1)
exit_err("sem_init");
puts("wait");
if (sem_wait(&sem) == -1)
exit_err("sem_wait");
puts("fork");
switch (fork()) {
case -1:
exit_err("fork");
case 0:
sleep(1);
puts("(child) post");
sem_post(&sem);
_exit(EXIT_SUCCESS);
default:
break;
}
puts("(parent) wait");
if (sem_wait(&sem) == -1)
exit_err("sem_wait2");
puts("(parent) done");
puts("Test named sem impl");
exit(EXIT_SUCCESS);
}