Serene Runtime 1.0.0-dev
C runtime for the Serene programming language
Loading...
Searching...
No Matches
08_pipe.c
Go to the documentation of this file.
1/* -*- C -*-
2 * Serene programming language
3 * Copyright (C) 2019-2026 Sameer Rahmani <[email protected]>
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <https://www.gnu.org/licenses/>.
17 */
18
19// Example 08 -- two fibers talking over a pipe with async IO.
20//
21// srn_fiber_read / srn_fiber_write look like blocking read/write, but they
22// suspend the calling fiber and hand the operation to the reactor rather than
23// blocking the worker os thread. The worker runs the other fiber meanwhile, and
24// the reactor wakes the issuer when its transfer completes. The descriptors must
25// be non-blocking so the reactor can drive them on readiness.
26//
27// A writer fiber sends a line into the pipe and a reader fiber pulls it out. On
28// a single worker whichever runs first parks in its IO call and yields to the
29// other, so the transfer completes cooperatively.
30
31#include <fcntl.h>
32#include <stdint.h>
33#include <stdio.h>
34#include <string.h>
35#include <unistd.h>
36
37#include <serene/rt/fiber/io.h>
38#include <serene/runtime.h>
39
40typedef struct {
41 int fd;
42 const char *msg;
44
45typedef struct {
46 int fd;
47 char *buf;
48 size_t cap;
50
51static void set_nonblock(int fd) {
52 int fl = fcntl(fd, F_GETFL, 0);
53 (void)fcntl(fd, F_SETFL, fl | O_NONBLOCK);
54}
55
56static srn_fiber_result_t writer(srn_context_t *ctx, void *arg) {
57 (void)ctx;
58 writer_args_t *w = arg;
59 srn_io_size_result_t r = srn_fiber_write(w->fd, w->msg, strlen(w->msg), -1);
60 if (HAS_ERROR(r)) {
61 printf("writer: error: %s\n", r.maybe_error->msg);
62 } else {
63 printf("writer: wrote %zu bytes\n", r.count);
64 }
65 close(w->fd); // signals EOF to the reader once the bytes are drained
66 return nullptr;
67}
68
69static srn_fiber_result_t reader(srn_context_t *ctx, void *arg) {
70 (void)ctx;
71 reader_args_t *rd = arg;
72 srn_io_size_result_t r = srn_fiber_read(rd->fd, rd->buf, rd->cap - 1, -1);
73 if (HAS_ERROR(r)) {
74 printf("reader: error: %s\n", r.maybe_error->msg);
75 } else {
76 rd->buf[r.count] = '\0';
77 printf("reader: read %zu bytes: \"%s\"\n", r.count, rd->buf);
78 }
79 close(rd->fd);
80 return nullptr;
81}
82
83int main(void) {
84 SERENE_RUNTIME_INIT_WITH_SCHED(engine, sched, nullptr);
85 srn_context_t *ctx = srn_context_make(engine);
86
87 int fds[2];
88 if (pipe(fds) != 0) {
89 perror("pipe");
90 return 1;
91 }
92 set_nonblock(fds[0]);
93 set_nonblock(fds[1]);
94
95 char buf[64] = {0};
96 writer_args_t w = {fds[1], "hello over a pipe"};
97 reader_args_t r = {fds[0], buf, sizeof(buf)};
98 (void)srn_fiber_spawn(ctx, writer, &w);
99 (void)srn_fiber_spawn(ctx, reader, &r);
100
101 srn_sched_run(sched, 1);
102
105 return 0;
106}
static void set_nonblock(int fd)
Definition 08_pipe.c:51
int main(void)
Definition 08_pipe.c:83
static srn_fiber_result_t writer(srn_context_t *ctx, void *arg)
Definition 08_pipe.c:56
static srn_fiber_result_t reader(srn_context_t *ctx, void *arg)
Definition 08_pipe.c:69
srn_context_t * srn_context_make(srn_engine_t *engine)
Make an empty context, by allocating a new memory block.
Definition context.c:39
int srn_context_release(srn_context_t *ctx)
Definition context.c:64
#define HAS_ERROR(x)
True when x – a value carrying an ERROR_HEADER – has an error attached.
Definition errors.h:63
srn_fiber_t * srn_fiber_spawn(srn_context_t *ctx, srn_fiber_entry_t entry, void *arg)
Make and schedule a fiber with every default, the engine's scheduler, the configured stack size,...
Definition fiber.c:247
void * srn_fiber_result_t
What a fiber's entry produces, type-erased.
Definition fiber.h:157
srn_io_size_result_t srn_fiber_write(int fd, const void *buf, size_t len, int64_t offset)
Write len bytes from buf to fd, suspending the calling fiber until the operation completes rather tha...
Definition io.c:296
srn_io_size_result_t srn_fiber_read(int fd, void *buf, size_t len, int64_t offset)
Read up to len bytes from fd into buf, suspending the calling fiber until the operation completes rat...
Definition io.c:284
The fiber facing IO API: blocking looking calls a fiber uses to do IO.
#define SERENE_RUNTIME_SHUTDOWN(engine)
Tear down what SERENE_RUNTIME_INIT brought up, in reverse order, the engine (reactor,...
Definition runtime.h:58
#define SERENE_RUNTIME_INIT_WITH_SCHED(engine, sched, config)
SERENE_RUNTIME_INIT plus a sched variable bound to the engine's scheduler, which every run and fiber ...
Definition runtime.h:46
void srn_sched_run(srn_scheduler_t *sched, size_t nworkers)
Run the scheduler with nworkers os threads draining it, returning once the pool goes quiescent (every...
Definition scheduler.c:843
char * buf
Definition 08_pipe.c:47
size_t cap
Definition 08_pipe.c:48
The result of a byte transfer op (read/write/sendto/recvmsg/sendmsg).
Definition io.h:76
size_t count
Definition io.h:78
const char * msg
Definition 08_pipe.c:42