Skip to content

Instantly share code, notes, and snippets.

@mu578
Last active December 18, 2023 02:57
Show Gist options
  • Save mu578/1bd0ce282a425b9947b87334545086fc to your computer and use it in GitHub Desktop.
Save mu578/1bd0ce282a425b9947b87334545086fc to your computer and use it in GitHub Desktop.
ping pong posix semaphore
// cc -pedantic -Wno-newline-eof -std=c99 ping.c -o ping_server.cmd
// cc -pedantic -Wno-newline-eof -std=c99 pong.c -o pong_client.cmd
// >$ ./ping_server.cmd & ./pong_client.cmd
// cc -pedantic -Wno-newline-eof -std=c99 ping_pong.c -o pong_ping.cmd
// >$ ./pong_ping.cmd
// cc -pedantic -Wno-newline-eof -std=c99 ping_pong_macos_gcd.c -o ping_pong_2.cmd
// >$ ./ping_pong_2.cmd
// cc -pedantic -Wno-newline-eof -std=c99 ping_pong_macos_gcd2.c -o ping_pong_3.cmd
// >$ ./ping_pong_3.cmd
------------------------------------------------------------------------------------------------------------------------
// ping.c
#include <sys/stat.h>
#include <semaphore.h>
#include <unistd.h>
int main(int argc, const char * argv[])
{
size_t i = 0;
sem_t * ping, * pong;
(void)argc;
(void)argv;
if (SEM_FAILED == (ping = sem_open("/ping", O_CREAT, 0644, 1))) {
return -1;
}
if (SEM_FAILED == (pong = sem_open("/pong", O_CREAT, 0644, 0))) {
sem_close(ping);
sem_unlink("/ping");
return -1;
}
for (; i < 10; i++) {
write(STDERR_FILENO, "ping\n", 5);
sem_post(pong);
sleep(1);
sem_wait(ping);
}
sem_close(pong);
sem_close(ping);
sem_unlink("/ping");
sem_unlink("/pong");
return 0;
}
/* EOF */
------------------------------------------------------------------------------------------------------------------------
// pong.c
#include <sys/stat.h>
#include <semaphore.h>
#include <unistd.h>
int main(int argc, const char * argv[])
{
size_t i = 0;
sem_t * ping, * pong;
(void)argc;
(void)argv;
if (SEM_FAILED == (ping = sem_open("/ping", O_CREAT, 0644, 1))) {
return -1;
}
if (SEM_FAILED == (pong = sem_open("/pong", O_CREAT, 0644, 0))) {
sem_close(ping);
return -1;
}
for (; i < 10; i++) {
sem_wait(pong);
write(STDERR_FILENO, "pong\n", 5);
sem_post(ping);
}
sem_close(pong);
sem_close(ping);
return 0;
}
/* EOF */
------------------------------------------------------------------------------------------------------------------------
// ping_pong.c
#include <sys/stat.h>
#include <fcntl.h>
#include <semaphore.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
struct thr_cookie
{
sem_t * u_ping;
sem_t * u_pong;
};
void * ping(void * arg)
{
sem_t * ping = ((struct thr_cookie *)arg)->u_ping;
sem_t * pong = ((struct thr_cookie *)arg)->u_pong;
sem_unlink("/ping");
sem_unlink("/pong");
if (SEM_FAILED == (ping = sem_open("/ping", O_CREAT, 0644, 1))) {
return NULL;
}
if (SEM_FAILED == (pong = sem_open("/pong", O_CREAT, 0644, 0))) {
sem_close(ping);
sem_unlink("/ping");
return NULL;
}
do {
write(STDOUT_FILENO, "ping\n", 5);
sem_post(pong);
sleep(1);
sem_wait(ping);
} while (1);
return NULL;
}
void * pong(void * arg)
{
sem_t * ping = ((struct thr_cookie *)arg)->u_ping;
sem_t * pong = ((struct thr_cookie *)arg)->u_pong;
if (SEM_FAILED == (ping = sem_open("/ping", O_CREAT, 0644, 1))) {
return NULL;
}
if (SEM_FAILED == (pong = sem_open("/pong", O_CREAT, 0644, 0))) {
sem_close(ping);
return NULL;
}
do {
sem_wait(pong);
write(STDOUT_FILENO, "pong\n", 5);
sem_post(ping);
} while (1);
return NULL;
}
int main(int argc, const char * argv[])
{
pthread_t thr_ping, thr_pong;
struct thr_cookie * cookie = calloc(1, sizeof(struct thr_cookie));
(void)argc;
(void)argv;
pthread_create(&thr_ping, NULL, ping, cookie);
pthread_create(&thr_pong, NULL, pong, cookie);
pthread_join(thr_ping, NULL);
pthread_join(thr_pong, NULL);
free(cookie);
return 0;
}
/* EOF */
------------------------------------------------------------------------------------------------------------------------
// ping_pong_macos_gcd.c
#include <sys/stat.h>
#include <fcntl.h>
# if __APPLE__ && __MACH__
# include <dispatch/dispatch.h>
# else
# include <semaphore.h>
# endif
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
struct thr_cookie
{
# if __APPLE__ && __MACH__
dispatch_semaphore_t u_ping;
dispatch_semaphore_t u_pong;
# else
sem_t u_ping;
sem_t u_pong;
# endif
};
void * ping(void * arg)
{
# if __APPLE__ && __MACH__
dispatch_semaphore_t ping = ((struct thr_cookie *)arg)->u_ping;
dispatch_semaphore_t pong = ((struct thr_cookie *)arg)->u_pong;
# else
sem_t ping = ((struct thr_cookie *)arg)->u_ping;
sem_t pong = ((struct thr_cookie *)arg)->u_pong;
# endif
int c = 5;
while (c-- > 0) {
# if __APPLE__ && __MACH__
dispatch_semaphore_wait(ping, DISPATCH_TIME_FOREVER);
# else
sem_wait(&ping);
# endif
write(STDOUT_FILENO, "ping\n", 5);
# if __APPLE__ && __MACH__
dispatch_semaphore_signal(pong);
# else
sem_post(&pong);
# endif
}
return NULL;
}
void * pong(void * arg)
{
# if __APPLE__ && __MACH__
dispatch_semaphore_t ping = ((struct thr_cookie *)arg)->u_ping;
dispatch_semaphore_t pong = ((struct thr_cookie *)arg)->u_pong;
# else
sem_t ping = ((struct thr_cookie *)arg)->u_ping;
sem_t pong = ((struct thr_cookie *)arg)->u_pong;
# endif
int c = 5;
while (c-- > 0) {
# if __APPLE__ && __MACH__
dispatch_semaphore_wait(pong, DISPATCH_TIME_FOREVER);
# else
sem_wait(&pong);
# endif
write(STDOUT_FILENO, "pong\n", 5);
# if __APPLE__ && __MACH__
dispatch_semaphore_signal(ping);
# else
sem_post(&ping);
# endif
}
return NULL;
}
int main(int argc, const char * argv[])
{
pthread_t thr_ping, thr_pong;
struct thr_cookie * cookie = calloc(1, sizeof(struct thr_cookie));
(void)argc;
(void)argv;
# if __APPLE__ && __MACH__
cookie->u_ping = dispatch_semaphore_create(1);
cookie->u_pong = dispatch_semaphore_create(0);
# else
sem_init(&cookie->u_ping, 0, 1);
sem_init(&cookie->u_pong, 0, 0);
# endif
pthread_create(&thr_ping, NULL, ping, cookie);
pthread_create(&thr_pong, NULL, pong, cookie);
pthread_join(thr_ping, NULL);
pthread_join(thr_pong, NULL);
# if __APPLE__ && __MACH__
dispatch_release(cookie->u_ping);
dispatch_release(cookie->u_pong);
# else
sem_destroy(&cookie->u_ping);
sem_destroy(&cookie->u_pong);
# endif
free(cookie);
return 0;
}
/* EOF */
------------------------------------------------------------------------------------------------------------------------
// ping_pong_macos_gcd2.c
#include <sys/stat.h>
#include <fcntl.h>
# if __APPLE__ && __MACH__
# include <dispatch/dispatch.h>
# else
# include <semaphore.h>
# endif
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
struct xsem
{
# if __APPLE__ && __MACH__
dispatch_semaphore_t u_sem;
# else
sem_t u_sem;
# endif
};
typedef struct xsem xsem_t;
static inline
long xsem_init(xsem_t * sem, unsigned int value)
{
# if __APPLE__ && __MACH__
sem->u_sem = dispatch_semaphore_create(value);
return 0;
# else
return sem_init(&sem->u_sem, 0, value);
# endif
}
static inline
long xsem_wait(xsem_t * sem)
{
long ret = -1;
# if __APPLE__ && __MACH__
ret = dispatch_semaphore_wait(sem->u_sem, DISPATCH_TIME_FOREVER) != 0 ? -1 : 0;
# else
do {
ret = sem_wait(&s->sem);
} while (ret == -1 && errno == EINTR);
# endif
return ret;
}
static inline
long xsem_trywait(xsem_t * sem)
{
# if __APPLE__ && __MACH__
return dispatch_semaphore_wait(sem->u_sem, DISPATCH_TIME_NOW) != 0 ? -1 : 0;
# else
return sem_trywait(&sem->u_sem);
# endif
}
static inline
long xsem_post(xsem_t * sem)
{
# if __APPLE__ && __MACH__
dispatch_semaphore_signal(sem->u_sem);
return 0;
# else
return sem_post(&sem->u_sem);
# endif
}
static inline
void xsem_destroy(xsem_t * sem)
{
# if __APPLE__ && __MACH__
dispatch_release(sem->u_sem);
# else
sem_destroy(&sem->u_sem);
# endif
}
struct thr_cookie
{
xsem_t u_ping;
xsem_t u_pong;
};
void * ping(void * arg)
{
xsem_t ping = ((struct thr_cookie *)arg)->u_ping;
xsem_t pong = ((struct thr_cookie *)arg)->u_pong;
int c = 5;
while (c-- > 0) {
xsem_wait(&ping);
write(STDOUT_FILENO, "ping\n", 5);
sleep(1);
xsem_post(&pong);
}
return NULL;
}
void * pong(void * arg)
{
xsem_t ping = ((struct thr_cookie *)arg)->u_ping;
xsem_t pong = ((struct thr_cookie *)arg)->u_pong;
int c = 5;
while (c-- > 0) {
xsem_wait(&pong);
write(STDOUT_FILENO, "pong\n", 5);
xsem_post(&ping);
}
return NULL;
}
int main(int argc, const char * argv[])
{
pthread_t thr_ping, thr_pong;
struct thr_cookie * cookie = calloc(1, sizeof(struct thr_cookie));
(void)argc;
(void)argv;
xsem_init(&cookie->u_ping, 1);
xsem_init(&cookie->u_pong, 0);
pthread_create(&thr_ping, NULL, ping, cookie);
pthread_create(&thr_pong, NULL, pong, cookie);
pthread_join(thr_ping, NULL);
pthread_join(thr_pong, NULL);
xsem_destroy(&cookie->u_ping);
xsem_destroy(&cookie->u_pong);
free(cookie);
return 0;
}
/* EOF */
------------------------------------------------------------------------------------------------------------------------
// ping_pong_pshared_emulation_draf.c
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
# if __APPLE__ && __MACH__
# include <dispatch/dispatch.h>
# endif
#include <semaphore.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
#include <errno.h>
#include <pthread.h>
struct xsem
{
char u_sid[24];
int u_isp;
# if __APPLE__ && __MACH__
dispatch_semaphore_t u_sem;
sem_t * u_shr;
# else
sem_t u_sem;
# endif
};
typedef struct xsem xsem_t;
static inline
long xsem_init(xsem_t * sem, int pshared, unsigned int value)
{
int ret = -1;
# if __APPLE__ && __MACH__
if (pshared) {
memset(sem->u_sid, 0, sizeof(char) * 24);
memcpy(sem->u_sid, "/tmp/semXXXXXXXXXXXXXXX", sizeof(char) * (24 - 1));
close(mkstemp(sem->u_sid));
unlink(sem->u_sid);
sem->u_shr = sem_open(sem->u_sid + 4, O_CREAT, O_RDWR, value);
if (SEM_FAILED != sem->u_shr) {
sem->u_isp = 1;
sem = mmap(sem->u_shr, sizeof(struct xsem), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
ret = 0;
} else {
sem->u_isp = 0;
ret = -1;
}
} else {
sem->u_isp = 0;
sem->u_sem = dispatch_semaphore_create(value);
ret = 0;
}
# else
if (pshared) {
sem->u_isp = 1;
ret = sem_init(&sem->u_sem, 1, value);
if (0 == ret) {
sem->u_isp = 1;
sem = mmap(NULL, sizeof(struct xsem), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
} else {
sem->u_isp = 0;
}
} else {
sem->u_isp = 0;
ret = sem_init(&sem->u_sem, 0, value);
}
# endif
return ret;
}
static inline
long xsem_wait(xsem_t * sem)
{
long ret = -1;
# if __APPLE__ && __MACH__
if (sem->u_isp) {
do {
ret = sem_wait(sem->u_shr);
} while (ret == -1 && errno == EINTR);
} else {
ret = dispatch_semaphore_wait(sem->u_sem, DISPATCH_TIME_FOREVER) != 0 ? -1 : 0;
}
# else
do {
ret = sem_wait(&sem->u_sem);
} while (ret == -1 && errno == EINTR);
# endif
return ret;
}
static inline
long xsem_trywait(xsem_t * sem)
{
# if __APPLE__ && __MACH__
if (sem->u_isp) {
return sem_trywait(sem->u_shr);
}
return dispatch_semaphore_wait(sem->u_sem, DISPATCH_TIME_NOW) != 0 ? -1 : 0;
# else
return sem_trywait(&sem->u_sem);
# endif
}
static inline
long xsem_post(xsem_t * sem)
{
# if __APPLE__ && __MACH__
if (sem->u_isp) {
return sem_post(sem->u_shr);
}
dispatch_semaphore_signal(sem->u_sem);
return 0;
# else
return sem_post(&sem->u_sem);
# endif
}
static inline
void xsem_destroy(xsem_t * sem)
{
# if __APPLE__ && __MACH__
if (sem->u_isp) {
sem_close(sem->u_shr);
sem_unlink(sem->u_sid + 4);
munmap(sem, sizeof(struct xsem));
} else {
dispatch_release(sem->u_sem);
}
# else
sem_destroy(&sem->u_sem);
if (sem->u_isp) {
munmap(sem, sizeof(struct xsem));
}
# endif
sem = NULL;
}
struct thr_cookie
{
xsem_t u_ping;
xsem_t u_pong;
};
void * ping(void * arg)
{
xsem_t ping = ((struct thr_cookie *)arg)->u_ping;
xsem_t pong = ((struct thr_cookie *)arg)->u_pong;
int c = 5;
do {
xsem_wait(&ping);
write(STDOUT_FILENO, "ping\n", 5);
sleep(1);
xsem_post(&pong);
} while (c-- > 0);
return NULL;
}
void * pong(void * arg)
{
xsem_t ping = ((struct thr_cookie *)arg)->u_ping;
xsem_t pong = ((struct thr_cookie *)arg)->u_pong;
int c = 5;
do {
xsem_wait(&pong);
write(STDOUT_FILENO, "pong\n", 5);
xsem_post(&ping);
} while (c-- > 0);
return NULL;
}
int main(int argc, const char * argv[])
{
pthread_t thr_ping, thr_pong;
struct thr_cookie * cookie = calloc(1, sizeof(struct thr_cookie));
(void)argc;
(void)argv;
xsem_init(&cookie->u_ping, 1, 1);
xsem_init(&cookie->u_pong, 1, 0);
pthread_create(&thr_ping, NULL, ping, cookie);
pthread_create(&thr_pong, NULL, pong, cookie);
pthread_join(thr_ping, NULL);
pthread_join(thr_pong, NULL);
xsem_destroy(&cookie->u_ping);
xsem_destroy(&cookie->u_pong);
free(cookie);
return 0;
}
/* EOF */
------------------------------------------------------------------------------------------------------------------------
// ping_pong_pshared_test.c
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <dispatch/dispatch.h>
#include <semaphore.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
#include <errno.h>
#include <pthread.h>
struct xsem
{
char u_sid[24];
int u_isp;
# if __APPLE__ && __MACH__
dispatch_semaphore_t u_sem;
sem_t * u_shr;
# else
sem_t u_sem;
# endif
};
typedef struct xsem * xsem_t;
static inline
long xsem_init(xsem_t * sem, int pshared, unsigned int value)
{
int ret = -1;
# if __APPLE__ && __MACH__
if (pshared) {
*sem = mmap(NULL, sizeof(struct xsem), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
memset((*sem)->u_sid, 0, sizeof(char) * 24);
memcpy((*sem)->u_sid, "/tmp/semXXXXXXXXXXXXXXX", sizeof(char) * (24 - 1));
close(mkstemp((*sem)->u_sid));
unlink((*sem)->u_sid);
(*sem)->u_shr = sem_open((*sem)->u_sid + 4, O_CREAT, O_RDWR, value);
if (SEM_FAILED != (*sem)->u_shr) {
(*sem)->u_isp = 1;
ret = 0;
} else {
(*sem)->u_isp = 0;
munmap(*sem, sizeof(struct xsem));
ret = -1;
}
} else {
(*sem)->u_isp = 0;
(*sem)->u_sem = dispatch_semaphore_create(value);
ret = 0;
}
# else
if (pshared) {
*sem = mmap(NULL, sizeof(struct xsem), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
ret = sem_init(&(*sem)->u_sem, 1, value);
if (0 == ret) {
(*sem)->u_isp = 1;
} else {
(*sem)->u_isp = 0;
munmap(*sem, sizeof(struct xsem));
ret = -1;
}
} else {
ret = sem_init(&(*sem)->u_sem, 0, value);
(*sem)->u_isp = 0;
}
# endif
return ret;
}
static inline
long xsem_wait(xsem_t * sem)
{
long ret = -1;
# if __APPLE__ && __MACH__
if ((*sem)->u_isp) {
do {
ret = sem_wait((*sem)->u_shr);
} while (ret == -1 && errno == EINTR);
} else {
ret = dispatch_semaphore_wait((*sem)->u_sem, DISPATCH_TIME_FOREVER) != 0 ? -1 : 0;
}
# else
do {
ret = sem_wait(&(*sem)->u_sem);
} while (ret == -1 && errno == EINTR);
# endif
return ret;
}
static inline
long xsem_trywait(xsem_t * sem)
{
# if __APPLE__ && __MACH__
if ((*sem)->u_isp) {
return sem_trywait((*sem)->u_shr);
}
return dispatch_semaphore_wait((*sem)->u_sem, DISPATCH_TIME_NOW) != 0 ? -1 : 0;
# else
return sem_trywait(&(*sem)->u_sem);
# endif
}
static inline
long xsem_post(xsem_t * sem)
{
# if __APPLE__ && __MACH__
if ((*sem)->u_isp) {
return sem_post((*sem)->u_shr);
}
dispatch_semaphore_signal((*sem)->u_sem);
return 0;
# else
return sem_post(&(*sem)->u_sem);
# endif
}
static inline
void xsem_destroy(xsem_t * sem)
{
# if __APPLE__ && __MACH__
if ((*sem)->u_isp) {
sem_close((*sem)->u_shr);
sem_unlink((*sem)->u_sid + 4);
munmap(*sem, sizeof(struct xsem));
} else {
dispatch_release((*sem)->u_sem);
}
# else
sem_destroy(&(*sem)->u_sem);
if ((*sem)->u_isp) {
munmap(sem, sizeof(struct xsem));
}
# endif
sem = NULL;
}
struct thr_cookie
{
xsem_t u_ping;
xsem_t u_pong;
};
void * ping(void * arg)
{
xsem_t ping = ((struct thr_cookie *)arg)->u_ping;
xsem_t pong = ((struct thr_cookie *)arg)->u_pong;
int c = 5;
do {
xsem_wait(&ping);
write(STDOUT_FILENO, "ping\n", 5);
sleep(1);
xsem_post(&pong);
} while (c-- > 0);
return NULL;
}
void * pong(void * arg)
{
xsem_t ping = ((struct thr_cookie *)arg)->u_ping;
xsem_t pong = ((struct thr_cookie *)arg)->u_pong;
int c = 5;
do {
xsem_wait(&pong);
write(STDOUT_FILENO, "pong\n", 5);
xsem_post(&ping);
} while (c-- > 0);
return NULL;
}
int main(int argc, const char * argv[])
{
size_t i = 0;
pid_t process[5];
xsem_t children[5];
xsem_t parent;
for (; i < 5; i++) {
xsem_init(&children[i], 1 , 0);
}
xsem_init(&parent, 1, 1);
for (i = 0; i < 5; i++) {
process[i]= fork();
if (0 == process[i] ) {
write(STDOUT_FILENO, "fork\n", 5);
sleep(1);
while (1) {
write(STDOUT_FILENO, "ping\n", 5);
sleep(1);
xsem_wait(&children[i]);
++i;
if(i >= 5) {
i = 0;
xsem_post(&parent);
}
write(STDOUT_FILENO, "pong\n", 5);
sleep(1);
xsem_post(&children[i]);
}
} else {
continue;
}
}
while (1) {
xsem_wait(&parent);
for (i = 0; i < 5; i++) {
xsem_post(&children[i]);
}
}
for (; i < 5; i++) {
xsem_destroy(&children[i]);
}
xsem_destroy(&parent);
return 0;
}
/* EOF */
@mu578
Copy link
Author

mu578 commented Sep 15, 2022

@maxencejded @peiliny my take on binary semaphores.

So it is destructive by pair run, that's just to demonstrate that posix named semaphores are by definition shared ; the rational would be to create then close once ; then processes re-open existing pair in read/write and write/read mode then close. The main process will unlink final when exiting. @see documentation.

I don't see much any advantage in using unnamed semaphores ; using a descriptor rather than accessing them by name. Macosx doesn't support posix unnamed semaphore for historical reason ; i.e internal per process open file table addr size i.e 64bit. Terry Lambert before leaving the core os team did some work in that area but it has never been upstreamed.

$ ./ping_server.cmd & ./pong_client.cmd 
[11] 58543
ping
pong
ping
pong
ping
pong
ping
pong
ping
pong
ping
pong
ping
pong
ping
pong
ping
pong
ping
pong

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment