std1.0.0-beta-7 SafeC docs

Source ipc/pipe_posix.sc

View in the repository

// SafeC Standard Library — Anonymous Pipes: POSIX backend
// (macOS / iOS / Linux / Android / FreeBSD — see pipe.h for the portable
// API and the full backend file list)
#pragma once
#include <std/stddef.h>
#include <std/ipc/pipe.h>

#define SAFEC_PIPE_F_GETFL 3
#define SAFEC_PIPE_F_SETFL 4
#define SAFEC_PIPE_O_NONBLOCK_BSD   0x0004
#define SAFEC_PIPE_O_NONBLOCK_LINUX 0x0800

namespace std {

extern int   pipe(int* pipefd);       // int pipefd[2]
extern ssize_t  read(int fd, unsigned char* buf, size_t count);
extern ssize_t  write(int fd, const unsigned char* buf, size_t count);
extern int   close(int fd);
extern int   fcntl(int fd, int cmd, ...);   // variadic: arm64 Apple passes the 3rd arg on the stack

inline int Pipe::init() {
    int fds[2];
    int rc;
    unsafe { rc = pipe(&fds[0]); }
    if (rc != 0) {
        return -1;
    }
    unsafe {
        self.read_fd  = (long long)fds[0];
        self.write_fd = (long long)fds[1];
    }
    return 0;
}

inline long long Pipe::read([]unsigned char buf_s) {
    unsigned long count = buf_s.len;
    &unsigned char buf;
    unsafe { buf = (&unsigned char)buf_s.ptr; }
    long n;
    unsafe { n = read((int)self.read_fd, (unsigned char*)buf, count); }
    return (long long)n;
}

inline long long Pipe::write([]const unsigned char buf_s) {
    unsigned long count = buf_s.len;
    const &unsigned char buf;
    unsafe { buf = (const &unsigned char)buf_s.ptr; }
    long n;
    unsafe { n = write((int)self.write_fd, (const unsigned char*)buf, count); }
    return (long long)n;
}

// macOS/BSD and Linux disagree on O_NONBLOCK's numeric value (see
// std/sched/io_nb_bsd.sc vs io_nb_linux.sc for the same split), so pick it
// by platform. (Trying one value and falling back on failure doesn't work:
// Linux's F_SETFL silently ignores unknown bits and returns 0.)
// F_GETFL/F_SETFL themselves are the same value, 3/4, on both.
#if defined(__linux__)
#define SAFEC_PIPE_O_NONBLOCK_ SAFEC_PIPE_O_NONBLOCK_LINUX
#else
#define SAFEC_PIPE_O_NONBLOCK_ SAFEC_PIPE_O_NONBLOCK_BSD
#endif
static int pipe_set_nonblocking_(int fd) {
    int flags;
    unsafe { flags = fcntl(fd, SAFEC_PIPE_F_GETFL, 0); }
    if (flags < 0) {
        return -1;
    }
    int rc;
    unsafe { rc = fcntl(fd, SAFEC_PIPE_F_SETFL, flags | SAFEC_PIPE_O_NONBLOCK_); }
    return rc;
}

inline int Pipe::set_read_nonblocking() {
    int fd;
    unsafe { fd = (int)self.read_fd; }
    return pipe_set_nonblocking_(fd);
}

inline int Pipe::set_write_nonblocking() {
    int fd;
    unsafe { fd = (int)self.write_fd; }
    return pipe_set_nonblocking_(fd);
}

inline int Pipe::close_read() {
    int fd;
    unsafe { fd = (int)self.read_fd; }
    int rc;
    unsafe { rc = close(fd); }
    return rc;
}

inline int Pipe::close_write() {
    int fd;
    unsafe { fd = (int)self.write_fd; }
    int rc;
    unsafe { rc = close(fd); }
    return rc;
}

} // namespace std