mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-05-27 15:52:28 +00:00
Introduce shm_open() and shm_unlink()
This commit is contained in:
parent
fadb64a2bf
commit
0b1acce680
9 changed files with 313 additions and 37 deletions
217
test/libc/calls/shm_open_test.c
Normal file
217
test/libc/calls/shm_open_test.c
Normal file
|
@ -0,0 +1,217 @@
|
|||
/* pshm_ucase_bounce.c
|
||||
Adapted from SHM_OPEN(3) in Linux Programmer's Manual
|
||||
Licensed under GNU General Public License v2 or later */
|
||||
|
||||
#include "libc/atomic.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
#include "libc/sysv/consts/s.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/thread/semaphore.h"
|
||||
|
||||
#define SHM_PATH "/fc7261622dd420d8"
|
||||
#define STRING_SEND "hello"
|
||||
#define STRING_RECV "HELLO"
|
||||
|
||||
struct shmbuf {
|
||||
sem_t sem1; /* POSIX unnamed semaphore */
|
||||
sem_t sem2; /* POSIX unnamed semaphore */
|
||||
size_t cnt; /* Number of bytes used in 'buf' */
|
||||
char buf[256]; /* Data being transferred */
|
||||
};
|
||||
|
||||
atomic_bool *ready;
|
||||
|
||||
wontreturn void Bouncer(void) {
|
||||
|
||||
/* Create shared memory object and set its size to the size
|
||||
of our structure. */
|
||||
int fd = shm_open(SHM_PATH, O_CREAT | O_EXCL | O_RDWR, S_IRUSR | S_IWUSR);
|
||||
if (fd == -1) {
|
||||
perror("shm_open(bouncer)");
|
||||
exit(1);
|
||||
}
|
||||
if (ftruncate(fd, sizeof(struct shmbuf)) == -1) {
|
||||
perror("ftruncate");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Map the object into the caller's address space. */
|
||||
struct shmbuf *shmp =
|
||||
mmap(NULL, sizeof(*shmp), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
if (shmp == MAP_FAILED) {
|
||||
perror("mmap");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Initialize semaphores as process-shared, with value 0. */
|
||||
if (sem_init(&shmp->sem1, 1, 0) == -1) {
|
||||
perror("sem_init-sem1");
|
||||
exit(1);
|
||||
}
|
||||
if (sem_init(&shmp->sem2, 1, 0) == -1) {
|
||||
perror("sem_init-sem2");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Let other process know it's ok to open. */
|
||||
*ready = true;
|
||||
|
||||
/* Wait for 'sem1' to be posted by peer before touching
|
||||
shared memory. */
|
||||
if (sem_wait(&shmp->sem1) == -1) {
|
||||
perror("sem_wait");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Convert data in shared memory into upper case. */
|
||||
for (int j = 0; j < shmp->cnt; j++) {
|
||||
shmp->buf[j] = toupper((unsigned char)shmp->buf[j]);
|
||||
}
|
||||
|
||||
/* Post 'sem2' to tell the peer that it can now
|
||||
access the modified data in shared memory. */
|
||||
if (sem_post(&shmp->sem2) == -1) {
|
||||
perror("sem_post");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
wontreturn void Sender(void) {
|
||||
|
||||
/* Wait for file to exist. */
|
||||
while (!*ready) donothing;
|
||||
|
||||
/* Open the existing shared memory object and map it
|
||||
into the caller's address space. */
|
||||
int fd = shm_open(SHM_PATH, O_RDWR, 0);
|
||||
if (fd == -1) {
|
||||
perror("shm_open(sender)");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
struct shmbuf *shmp =
|
||||
mmap(NULL, sizeof(*shmp), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
if (shmp == MAP_FAILED) {
|
||||
perror("mmap");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Copy data into the shared memory object. */
|
||||
shmp->cnt = strlen(STRING_SEND);
|
||||
strcpy(shmp->buf, STRING_SEND);
|
||||
|
||||
/* Tell peer that it can now access shared memory. */
|
||||
if (sem_post(&shmp->sem1) == -1) {
|
||||
perror("sem_post");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Wait until peer says that it has finished accessing
|
||||
the shared memory. */
|
||||
if (sem_wait(&shmp->sem2) == -1) {
|
||||
perror("sem_wait");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Write modified data in shared memory to standard output. */
|
||||
if (strcmp(shmp->buf, STRING_RECV)) {
|
||||
tinyprint(2, program_invocation_name,
|
||||
": received wrong string: ", shmp->buf, "\n", NULL);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Unlink the shared memory object. Even if the peer process
|
||||
is still using the object, this is okay. The object will
|
||||
be removed only after all open references are closed. */
|
||||
if (shm_unlink(SHM_PATH)) {
|
||||
if (IsWindows() && errno == EACCES) {
|
||||
// TODO(jart): Make unlink() work better on Windows.
|
||||
} else {
|
||||
perror("shm_unlink");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int pid1;
|
||||
int pid2;
|
||||
|
||||
void OnExit(void) {
|
||||
kill(pid1, SIGKILL);
|
||||
kill(pid2, SIGKILL);
|
||||
shm_unlink(SHM_PATH);
|
||||
}
|
||||
|
||||
void OnTimeout(int sig) {
|
||||
tinyprint(2, program_invocation_name, ": test timed out!\n", NULL);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
// create synchronization object
|
||||
ready = _mapshared(1);
|
||||
|
||||
// create bouncer
|
||||
pid1 = fork();
|
||||
if (pid1 == -1) {
|
||||
perror("fork");
|
||||
exit(1);
|
||||
}
|
||||
if (!pid1) {
|
||||
Bouncer();
|
||||
}
|
||||
|
||||
// create sender
|
||||
pid2 = fork();
|
||||
if (pid1 == -1) {
|
||||
perror("fork");
|
||||
kill(pid1, SIGKILL);
|
||||
exit(1);
|
||||
}
|
||||
if (!pid2) {
|
||||
Sender();
|
||||
}
|
||||
|
||||
// set limit
|
||||
atexit(OnExit);
|
||||
signal(SIGALRM, OnTimeout);
|
||||
alarm(1);
|
||||
|
||||
// wait for children
|
||||
for (;;) {
|
||||
int child, status;
|
||||
child = wait(&status);
|
||||
if (child == -1) {
|
||||
if (errno == ECHILD) {
|
||||
break;
|
||||
}
|
||||
perror("wait");
|
||||
exit(1);
|
||||
}
|
||||
if (status) {
|
||||
if (WIFEXITED(status)) {
|
||||
exit(WEXITSTATUS(status));
|
||||
} else {
|
||||
raise(WTERMSIG(status));
|
||||
exit(128 + WTERMSIG(status));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// report success
|
||||
exit(0);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue