mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-03-03 07:29:23 +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
|
@ -158,6 +158,8 @@ int setregid(unsigned, unsigned);
|
|||
int setreuid(unsigned, unsigned);
|
||||
int setsid(void);
|
||||
int setuid(unsigned);
|
||||
int shm_open(const char *, int, unsigned);
|
||||
int shm_unlink(const char *);
|
||||
int sigignore(int);
|
||||
int siginterrupt(int, int);
|
||||
int symlink(const char *, const char *);
|
||||
|
@ -211,36 +213,37 @@ int madvise(void *, uint64_t, int);
|
|||
#ifdef _COSMO_SOURCE
|
||||
bool32 fdexists(int);
|
||||
bool32 fileexists(const char *);
|
||||
bool32 ischardev(int);
|
||||
bool32 isdirectory(const char *);
|
||||
bool32 isexecutable(const char *);
|
||||
bool32 isregularfile(const char *);
|
||||
bool32 issymlink(const char *);
|
||||
bool32 ischardev(int);
|
||||
char *commandv(const char *, char *, size_t);
|
||||
int clone(void *, void *, size_t, int, void *, void *, void *, void *);
|
||||
int fadvise(int, uint64_t, uint64_t, int);
|
||||
int makedirs(const char *, unsigned);
|
||||
int pivot_root(const char *, const char *);
|
||||
int pledge(const char *, const char *);
|
||||
int seccomp(unsigned, unsigned, void *);
|
||||
int sys_iopl(int);
|
||||
int sys_ioprio_get(int, int);
|
||||
int sys_ioprio_set(int, int, int);
|
||||
int sys_mlock(const void *, size_t);
|
||||
int sys_mlock2(const void *, size_t, int);
|
||||
int sys_mlockall(int);
|
||||
int sys_personality(uint64_t);
|
||||
int sys_munlock(const void *, size_t);
|
||||
int sys_munlockall(void);
|
||||
int sys_personality(uint64_t);
|
||||
int sys_ptrace(int, ...);
|
||||
int sys_sysctl(const int *, unsigned, void *, size_t *, void *, size_t);
|
||||
int sys_ioprio_get(int, int);
|
||||
int sys_ioprio_set(int, int, int);
|
||||
int tmpfd(void);
|
||||
int touch(const char *, unsigned);
|
||||
int unveil(const char *, const char *);
|
||||
long ptrace(int, ...);
|
||||
int fadvise(int, uint64_t, uint64_t, int);
|
||||
ssize_t copyfd(int, int, size_t);
|
||||
ssize_t readansi(int, char *, size_t);
|
||||
ssize_t tinyprint(int, const char *, ...) nullterminated();
|
||||
void shm_path_np(const char *, char[hasatleast 78]);
|
||||
#endif /* _COSMO_SOURCE */
|
||||
|
||||
int __wifstopped(int) pureconst;
|
||||
|
|
|
@ -91,11 +91,9 @@ textwindows int GetNtOpenFlags(int flags, int mode, uint32_t *out_perm,
|
|||
|
||||
// Be as generous as possible in sharing file access. Not doing this
|
||||
// you'll quickly find yourself no longer able to administer Windows
|
||||
if (flags & _O_EXCL) {
|
||||
share = kNtFileShareExclusive;
|
||||
} else {
|
||||
share = kNtFileShareRead | kNtFileShareWrite | kNtFileShareDelete;
|
||||
}
|
||||
// and we need this to be the case even in O_EXCL mode otherwise the
|
||||
// shm_open_test.c won't behave consistently on Windows like on UNIX
|
||||
share = kNtFileShareRead | kNtFileShareWrite | kNtFileShareDelete;
|
||||
|
||||
// These POSIX to WIN32 mappings are relatively straightforward.
|
||||
if (flags & _O_EXCL) {
|
||||
|
|
45
libc/calls/shm_open.c
Normal file
45
libc/calls/shm_open.c
Normal file
|
@ -0,0 +1,45 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2023 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/blockcancel.internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Opens POSIX named memory object.
|
||||
*
|
||||
* @param name should begin with a `/` and shouldn't contain subsequent
|
||||
* slash characters, and furthermore shouldn't exceed NAME_MAX, for
|
||||
* maximum portability; POSIX defines it as opening a multi-process
|
||||
* object and leaves all other names implementation defined; and we
|
||||
* choose (in this implementation) to define those names as meaning
|
||||
* the same thing while not imposing any length limit; cosmo always
|
||||
* feeds your name through BLAKE2B to create a `.sem` file existing
|
||||
* under `/dev/shm` if available, otherwise it will go under `/tmp`
|
||||
* @return open file descriptor, or -1 w/ errno
|
||||
*/
|
||||
int shm_open(const char *name, int oflag, unsigned mode) {
|
||||
int fd;
|
||||
char path[78];
|
||||
shm_path_np(name, path);
|
||||
BLOCK_CANCELATION;
|
||||
fd = openat(AT_FDCWD, path, oflag, mode);
|
||||
ALLOW_CANCELATION;
|
||||
return fd;
|
||||
}
|
|
@ -20,36 +20,26 @@
|
|||
#include "libc/dce.h"
|
||||
#include "libc/str/blake2.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/thread/thread.h"
|
||||
|
||||
/**
|
||||
* Returns filesystem pathname of named semaphore.
|
||||
*
|
||||
* @param name is `name` of semaphore which should begin with slash
|
||||
* @param buf is temporary storage with at least `size` bytes
|
||||
* @param size is size of `buf` in bytes
|
||||
* @param buf is temporary storage with at least 78 bytes
|
||||
* @return pointer to file system path
|
||||
* @raise ENAMETOOLONG if constructed path would exceed `size`
|
||||
*/
|
||||
const char *sem_path_np(const char *name, char *buf, size_t size) {
|
||||
void shm_path_np(const char *name, char buf[hasatleast 78]) {
|
||||
char *p;
|
||||
unsigned n;
|
||||
const char *path, *a;
|
||||
const char *a;
|
||||
uint8_t digest[BLAKE2B256_DIGEST_LENGTH];
|
||||
a = "/tmp/", n = 5;
|
||||
if (IsLinux() && isdirectory("/dev/shm")) {
|
||||
a = "/dev/shm/", n = 9;
|
||||
}
|
||||
if (n + BLAKE2B256_DIGEST_LENGTH * 2 + 4 < size) {
|
||||
BLAKE2B256(name, strlen(name), digest);
|
||||
p = mempcpy(buf, a, n);
|
||||
p = hexpcpy(p, digest, BLAKE2B256_DIGEST_LENGTH);
|
||||
p = mempcpy(p, ".sem", 5);
|
||||
path = buf;
|
||||
} else {
|
||||
enametoolong();
|
||||
path = 0;
|
||||
}
|
||||
return path;
|
||||
BLAKE2B256(name, strlen(name), digest);
|
||||
p = mempcpy(buf, a, n);
|
||||
p = hexpcpy(p, digest, BLAKE2B256_DIGEST_LENGTH);
|
||||
mempcpy(p, ".sem", 5);
|
||||
}
|
28
libc/calls/shm_unlink.c
Normal file
28
libc/calls/shm_unlink.c
Normal file
|
@ -0,0 +1,28 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2023 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
|
||||
/**
|
||||
* Deletes POSIX named memory object.
|
||||
*/
|
||||
int shm_unlink(const char *name) {
|
||||
char path[78];
|
||||
shm_path_np(name, path);
|
||||
return unlink(path);
|
||||
}
|
|
@ -171,9 +171,8 @@ static struct Semaphore *sem_open_get(const sem_t *sem,
|
|||
sem_t *sem_open(const char *name, int oflag, ...) {
|
||||
sem_t *sem;
|
||||
va_list va;
|
||||
const char *path;
|
||||
char path[78];
|
||||
struct Semaphore *s;
|
||||
char pathbuf[PATH_MAX];
|
||||
unsigned mode = 0, value = 0;
|
||||
|
||||
va_start(va, oflag);
|
||||
|
@ -206,9 +205,7 @@ sem_t *sem_open(const char *name, int oflag, ...) {
|
|||
return SEM_FAILED;
|
||||
}
|
||||
}
|
||||
if (!(path = sem_path_np(name, pathbuf, sizeof(pathbuf)))) {
|
||||
return SEM_FAILED;
|
||||
}
|
||||
shm_path_np(name, path);
|
||||
BLOCK_CANCELATION;
|
||||
sem_open_init();
|
||||
sem_open_lock();
|
||||
|
@ -321,10 +318,9 @@ int sem_close(sem_t *sem) {
|
|||
* @raise ENAMETOOLONG if too long
|
||||
*/
|
||||
int sem_unlink(const char *name) {
|
||||
const char *path;
|
||||
char path[78];
|
||||
int rc, e = errno;
|
||||
struct Semaphore *s;
|
||||
char pathbuf[PATH_MAX];
|
||||
|
||||
#if 0
|
||||
if (IsXnuSilicon()) {
|
||||
|
@ -332,7 +328,7 @@ int sem_unlink(const char *name) {
|
|||
}
|
||||
#endif
|
||||
|
||||
if (!(path = sem_path_np(name, pathbuf, sizeof(pathbuf)))) return -1;
|
||||
shm_path_np(name, path);
|
||||
if ((rc = unlink(path)) == -1 && IsWindows() && errno == EACCES) {
|
||||
sem_open_init();
|
||||
sem_open_lock();
|
||||
|
|
|
@ -38,7 +38,6 @@ int sem_getvalue(sem_t *, int *);
|
|||
sem_t *sem_open(const char *, int, ...);
|
||||
int sem_close(sem_t *);
|
||||
int sem_unlink(const char *);
|
||||
const char *sem_path_np(const char *, char *, size_t);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
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);
|
||||
}
|
|
@ -46,7 +46,7 @@ void IgnoreStderr(void) {
|
|||
|
||||
const char *SemPath(const char *name) {
|
||||
static _Thread_local char buf[PATH_MAX];
|
||||
return sem_path_np(name, buf, sizeof(buf));
|
||||
return shm_path_np(name, buf, sizeof(buf));
|
||||
}
|
||||
|
||||
void SetUp(void) {
|
||||
|
|
Loading…
Add table
Reference in a new issue