From bd3936c7edf4cbb13c26c243351bcb35e890e6c7 Mon Sep 17 00:00:00 2001
From: Norman Feske <norman.feske@genode-labs.com>
Date: Tue, 14 Mar 2023 15:07:13 +0100
Subject: [PATCH] Test for combining select with a pipe

The test exercises the VFS's read-ready mechanism when using the
vfs_pipe plugin.

Issue #4785
---
 repos/gems/run/depot_autopilot.run            |  1 +
 .../recipes/pkg/test-pipe_read_ready/README   |  1 +
 .../recipes/pkg/test-pipe_read_ready/archives |  6 ++
 .../recipes/pkg/test-pipe_read_ready/hash     |  1 +
 .../recipes/pkg/test-pipe_read_ready/runtime  | 73 +++++++++++++++++++
 .../src/test-pipe_read_ready/content.mk       | 10 +++
 .../recipes/src/test-pipe_read_ready/hash     |  1 +
 .../src/test-pipe_read_ready/used_apis        |  2 +
 .../src/test/pipe_read_ready/counter/main.c   | 23 ++++++
 .../test/pipe_read_ready/counter/target.mk    |  3 +
 .../src/test/pipe_read_ready/select/main.c    | 38 ++++++++++
 .../src/test/pipe_read_ready/select/target.mk |  3 +
 12 files changed, 162 insertions(+)
 create mode 100644 repos/libports/recipes/pkg/test-pipe_read_ready/README
 create mode 100644 repos/libports/recipes/pkg/test-pipe_read_ready/archives
 create mode 100644 repos/libports/recipes/pkg/test-pipe_read_ready/hash
 create mode 100644 repos/libports/recipes/pkg/test-pipe_read_ready/runtime
 create mode 100644 repos/libports/recipes/src/test-pipe_read_ready/content.mk
 create mode 100644 repos/libports/recipes/src/test-pipe_read_ready/hash
 create mode 100644 repos/libports/recipes/src/test-pipe_read_ready/used_apis
 create mode 100644 repos/libports/src/test/pipe_read_ready/counter/main.c
 create mode 100644 repos/libports/src/test/pipe_read_ready/counter/target.mk
 create mode 100644 repos/libports/src/test/pipe_read_ready/select/main.c
 create mode 100644 repos/libports/src/test/pipe_read_ready/select/target.mk

diff --git a/repos/gems/run/depot_autopilot.run b/repos/gems/run/depot_autopilot.run
index 605d6f4e17..1a84d0a02e 100644
--- a/repos/gems/run/depot_autopilot.run
+++ b/repos/gems/run/depot_autopilot.run
@@ -692,6 +692,7 @@ set default_test_pkgs {
 	test-nic_loopback
 	test-part_block_gpt
 	test-part_block_mbr
+	test-pipe_read_ready
 	test-pthread
 	test-ram_fs_chunk
 	test-read_only_rom
diff --git a/repos/libports/recipes/pkg/test-pipe_read_ready/README b/repos/libports/recipes/pkg/test-pipe_read_ready/README
new file mode 100644
index 0000000000..eea1bee388
--- /dev/null
+++ b/repos/libports/recipes/pkg/test-pipe_read_ready/README
@@ -0,0 +1 @@
+Test for using select to wait for a pipe at a VFS server
diff --git a/repos/libports/recipes/pkg/test-pipe_read_ready/archives b/repos/libports/recipes/pkg/test-pipe_read_ready/archives
new file mode 100644
index 0000000000..cfa04372d6
--- /dev/null
+++ b/repos/libports/recipes/pkg/test-pipe_read_ready/archives
@@ -0,0 +1,6 @@
+_/src/init
+_/src/libc
+_/src/vfs
+_/src/vfs_pipe
+_/src/posix
+_/src/test-pipe_read_ready
diff --git a/repos/libports/recipes/pkg/test-pipe_read_ready/hash b/repos/libports/recipes/pkg/test-pipe_read_ready/hash
new file mode 100644
index 0000000000..9e4ff58b51
--- /dev/null
+++ b/repos/libports/recipes/pkg/test-pipe_read_ready/hash
@@ -0,0 +1 @@
+2023-03-15 2d8860bc863bcb722b03982ec1b68bc21fcf6553
diff --git a/repos/libports/recipes/pkg/test-pipe_read_ready/runtime b/repos/libports/recipes/pkg/test-pipe_read_ready/runtime
new file mode 100644
index 0000000000..b06ff5624a
--- /dev/null
+++ b/repos/libports/recipes/pkg/test-pipe_read_ready/runtime
@@ -0,0 +1,73 @@
+<runtime ram="32M" caps="1000" binary="init">
+
+	<requires> <timer/> </requires>
+
+	<events>
+		<timeout meaning="failed" sec="30" />
+		<log meaning="succeeded">[init -> select] 3</log>
+	</events>
+
+	<content>
+		<rom label="ld.lib.so"/>
+		<rom label="libc.lib.so"/>
+		<rom label="libm.lib.so"/>
+		<rom label="posix.lib.so"/>
+		<rom label="vfs"/>
+		<rom label="vfs.lib.so"/>
+		<rom label="vfs_pipe.lib.so"/>
+		<rom label="test-pipe_read_ready_counter"/>
+		<rom label="test-pipe_read_ready_select"/>
+	</content>
+
+	<config>
+		<parent-provides>
+			<service name="ROM"/>
+			<service name="PD"/>
+			<service name="RM"/>
+			<service name="CPU"/>
+			<service name="LOG"/>
+			<service name="Timer"/>
+		</parent-provides>
+
+		<default-route>
+			<any-service> <parent/> <any-child/> </any-service>
+		</default-route>
+
+		<default caps="100"/>
+
+		<start name="vfs">
+			<resource name="RAM" quantum="12M"/>
+			<provides> <service name="File_system"/> </provides>
+			<config>
+				<vfs> <pipe> <fifo name="fifo"/> </pipe> </vfs>
+				<default-policy root="/" writeable="yes"/>
+			</config>
+		</start>
+
+		<start name="select">
+			<resource name="RAM" quantum="3M"/>
+			<binary name="test-pipe_read_ready_select"/>
+			<config>
+				<vfs>
+					<dir name="dev"> <log/> </dir>
+					<dir name="rw"> <fs/> </dir>
+				</vfs>
+				<libc stdin="/rw/fifo" stdout="/dev/log" stderr="/dev/log"/>
+			</config>
+		</start>
+
+		<start name="counter" caps="120">
+			<resource name="RAM" quantum="3M"/>
+			<binary name="test-pipe_read_ready_counter"/>
+			<config>
+				<vfs>
+					<dir name="dev"> <null/> <fs/> <log/> </dir>
+					<dir name="rw"> <fs/> </dir>
+				</vfs>
+				<libc stdin="/dev/null" stdout="/rw/fifo" stderr="/dev/log"/>
+			</config>
+		</start>
+
+	</config>
+
+</runtime>
diff --git a/repos/libports/recipes/src/test-pipe_read_ready/content.mk b/repos/libports/recipes/src/test-pipe_read_ready/content.mk
new file mode 100644
index 0000000000..fd1fb11356
--- /dev/null
+++ b/repos/libports/recipes/src/test-pipe_read_ready/content.mk
@@ -0,0 +1,10 @@
+MIRROR_FROM_REP_DIR := src/test/pipe_read_ready
+
+content: $(MIRROR_FROM_REP_DIR) LICENSE
+
+$(MIRROR_FROM_REP_DIR):
+	$(mirror_from_rep_dir)
+
+LICENSE:
+	cp $(GENODE_DIR)/LICENSE $@
+
diff --git a/repos/libports/recipes/src/test-pipe_read_ready/hash b/repos/libports/recipes/src/test-pipe_read_ready/hash
new file mode 100644
index 0000000000..1140baa086
--- /dev/null
+++ b/repos/libports/recipes/src/test-pipe_read_ready/hash
@@ -0,0 +1 @@
+2023-03-15 b7831174a141db784aa219327a3e40ac726e07f1
diff --git a/repos/libports/recipes/src/test-pipe_read_ready/used_apis b/repos/libports/recipes/src/test-pipe_read_ready/used_apis
new file mode 100644
index 0000000000..0c483273a8
--- /dev/null
+++ b/repos/libports/recipes/src/test-pipe_read_ready/used_apis
@@ -0,0 +1,2 @@
+libc
+posix
diff --git a/repos/libports/src/test/pipe_read_ready/counter/main.c b/repos/libports/src/test/pipe_read_ready/counter/main.c
new file mode 100644
index 0000000000..64d139ac99
--- /dev/null
+++ b/repos/libports/src/test/pipe_read_ready/counter/main.c
@@ -0,0 +1,23 @@
+/*
+ * \brief  Print counter every second
+ * \author Norman Feske
+ * \date   2023-03-14
+ */
+
+/*
+ * Copyright (C) 2023 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+
+int main(int argc, char **argv)
+{
+	for (unsigned count = 0; ; count++) {
+		printf("%d\n", count);
+		sleep(1);
+	}
+}
diff --git a/repos/libports/src/test/pipe_read_ready/counter/target.mk b/repos/libports/src/test/pipe_read_ready/counter/target.mk
new file mode 100644
index 0000000000..e2b5c556b4
--- /dev/null
+++ b/repos/libports/src/test/pipe_read_ready/counter/target.mk
@@ -0,0 +1,3 @@
+TARGET := test-pipe_read_ready_counter
+SRC_C  := main.c
+LIBS   += posix
diff --git a/repos/libports/src/test/pipe_read_ready/select/main.c b/repos/libports/src/test/pipe_read_ready/select/main.c
new file mode 100644
index 0000000000..1dbffbd504
--- /dev/null
+++ b/repos/libports/src/test/pipe_read_ready/select/main.c
@@ -0,0 +1,38 @@
+/*
+ * \brief  Watch stdin using select and forward data to stout
+ * \author Norman Feske
+ * \date   2023-03-15
+ */
+
+/*
+ * Copyright (C) 2023 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/select.h>
+
+int main(int argc, char **argv)
+{
+	for (;;) {
+
+		/* wait until stdin becomes ready to read */
+		fd_set fds;
+		FD_ZERO(&fds);
+		FD_SET(STDIN_FILENO, &fds);
+		select(1, &fds, NULL, NULL, NULL);
+
+		char buffer[4096];
+		ssize_t const bytes = read(STDIN_FILENO, buffer, sizeof(buffer));
+
+		if (bytes == -1)
+			fprintf(stderr, "read failed, errno=%d\n", errno);
+
+		if (bytes > 0)
+			write(STDOUT_FILENO, buffer, bytes);
+	}
+}
diff --git a/repos/libports/src/test/pipe_read_ready/select/target.mk b/repos/libports/src/test/pipe_read_ready/select/target.mk
new file mode 100644
index 0000000000..e2cd27e24d
--- /dev/null
+++ b/repos/libports/src/test/pipe_read_ready/select/target.mk
@@ -0,0 +1,3 @@
+TARGET := test-pipe_read_ready_select
+SRC_C  := main.c
+LIBS   += posix