commit 454ef1d
zzo38
·
2024-09-05 21:02:10 +0000 UTC
parent 0da046e
Implement the subprocess extension. This has not been tested yet. Co-authored-by: d_m <d_m@plastic-idolatry.com>
3 files changed,
+182,
-0
+2,
-0
1@@ -341,6 +341,8 @@ See the file extension.doc for the definition of the extensions.
2
3 * 970b5a0c-2c44-11ee-ac3b-002618745416
4
5+* 9c5f1356-6bc5-11ef-a6c9-002618745416 (also requires -I and -Y)
6+
7
8 === Memory/device scripts ===
9
+16,
-0
1@@ -20,6 +20,8 @@ it conflicts with other extensions.)
2
3 See: https://git.phial.org/d6/uxn11/src/branch/d6/multiprocess/console.txt
4
5+(This extension may be obsolete; see 9c5f1356-6bc5-11ef-a6c9-002618745416)
6+
7
8 === 80175132-e263-11ed-b8c9-002618745416 (Colours) ===
9
10@@ -54,6 +56,20 @@ when drawing sprites.
11 Other bits are currently unused.
12
13
14+=== 9c5f1356-6bc5-11ef-a6c9-002618745416 (Subprocess) ===
15+
16+This is an extension for handling subprocesses. The device number must
17+be 0x10 and the current version number is 1.
18+
19+15 = Subprocess status
20+16 = Subprocess exit code
21+1C = Subprocess command line *
22+1E = Subprocess mode
23+1F = Start subprocess
24+
25+(This documentation is incomplete)
26+
27+
28 === b076ddca-db5a-11ee-bddb-002618745416 (Extended text input) ===
29
30 (DRAFT)
M
main.c
+164,
-0
1@@ -16,6 +16,20 @@ exit
2 #include <time.h>
3 #include <unistd.h>
4
5+// Subprocess support
6+#include <signal.h>
7+#include <sys/wait.h>
8+
9+#ifdef __linux
10+#include <pty.h>
11+#include <sys/prctl.h>
12+#endif
13+
14+#ifdef __NetBSD__
15+#include <sys/ioctl.h>
16+#include <util.h>
17+#endif
18+
19 static const Uint8 fontdata[]={ // font for built-in menus
20 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x78,0x78,0x30,0x30,0x00,0x30,0x00,
21 0x6C,0x6C,0x6C,0x00,0x00,0x00,0x00,0x00,0x6C,0x6C,0xFE,0x6C,0xFE,0x6C,0x6C,0x00,
22@@ -427,10 +441,156 @@ static void system_out(Device*dev,Uint8 id) {
23 }
24 }
25
26+// Subprocess support
27+
28+static char enable_subprocess=0;
29+static char *fork_args[4] = {"/bin/sh", "-c", "", NULL};
30+static int child_mode;
31+static int to_child_fd[2];
32+static int from_child_fd[2];
33+static int saved_in;
34+static int saved_out;
35+static pid_t child_pid;
36+
37+/* call after we're sure the process has exited */
38+static void console_clean_after_child(void) {
39+ child_pid = 0;
40+ if(child_mode & 0x01) {
41+ close(to_child_fd[1]);
42+ dup2(saved_out, 1);
43+ }
44+ if(child_mode & (0x04 | 0x02)) {
45+ close(from_child_fd[0]);
46+ dup2(saved_in, 0);
47+ }
48+ child_mode = 0;
49+ saved_in = -1;
50+ saved_out = -1;
51+}
52+
53+static void console_start_fork_pipe(Device*dev) {
54+ pid_t pid;
55+ pid_t parent_pid = getpid();
56+ int addr = GET16(dev->d+12);
57+ fflush(stdout);
58+ if(child_mode & 0x08) {
59+ dev->d[6] = dev->d[5] = 0;
60+ return;
61+ }
62+ if(child_mode & 0x01) {
63+ /* parent writes to child's stdin */
64+ if(pipe(to_child_fd) == -1) {
65+ dev->d[6] = dev->d[5] = 255;
66+ fprintf(stderr, "pipe error: to child\n");
67+ return;
68+ }
69+ }
70+ if(child_mode & (0x04 | 0x02)) {
71+ /* parent reads from child's stdout and/or stderr */
72+ if(pipe(from_child_fd) == -1) {
73+ dev->d[6] = dev->d[5] = 255;
74+ fprintf(stderr, "pipe error: from child\n");
75+ return;
76+ }
77+ }
78+
79+ fork_args[2] = (char *)(mem + GET16(dev->d+12));
80+ pid = fork();
81+ if(pid < 0) { /* failure */
82+ dev->d[6] = dev->d[5] = 255;
83+ fprintf(stderr, "fork failure\n");
84+ } else if(pid == 0) { /* child */
85+
86+#ifdef __linux__
87+ int r = prctl(PR_SET_PDEATHSIG, SIGTERM);
88+ if(r == -1) {
89+ perror(0);
90+ exit(6);
91+ }
92+ if(getppid() != parent_pid) exit(13);
93+#endif
94+
95+ if(child_mode & 0x01) {
96+ dup2(to_child_fd[0], 0);
97+ close(to_child_fd[1]);
98+ }
99+ if(child_mode & (0x04 | 0x02)) {
100+ if(child_mode & 0x02) dup2(from_child_fd[1], 1);
101+ if(child_mode & 0x04) dup2(from_child_fd[1], 2);
102+ close(from_child_fd[0]);
103+ }
104+ fflush(stdout);
105+ execvp(fork_args[0], fork_args);
106+ exit(1);
107+ } else { /*parent*/
108+ child_pid = pid;
109+ dev->d[5] = 1;
110+ dev->d[6] = 0;
111+ if(child_mode & 0x01) {
112+ saved_out = dup(1);
113+ dup2(to_child_fd[1], 1);
114+ close(to_child_fd[0]);
115+ }
116+ if(child_mode & (0x04 | 0x02)) {
117+ saved_in = dup(0);
118+ dup2(from_child_fd[0], 0);
119+ close(from_child_fd[1]);
120+ }
121+ }
122+}
123+
124+static void console_check_child(Device*dev) {
125+ int wstatus;
126+ if(child_pid) {
127+ if(waitpid(child_pid, &wstatus, WNOHANG)) {
128+ dev->d[5] = 255;
129+ dev->d[6] = WEXITSTATUS(wstatus);
130+ console_clean_after_child();
131+ } else {
132+ dev->d[5] = 1;
133+ dev->d[6] = 0;
134+ }
135+ }
136+}
137+
138+static void console_kill_child(Device*dev) {
139+ int wstatus;
140+ if(child_pid) {
141+ kill(child_pid, 9);
142+ if(waitpid(child_pid, &wstatus, WNOHANG)) {
143+ dev->d[5] = 255;
144+ dev->d[6] = WEXITSTATUS(wstatus);
145+ console_clean_after_child();
146+ }
147+ }
148+}
149+
150+static void console_start_fork(Device*dev) {
151+ fflush(stderr);
152+ console_kill_child(dev);
153+ child_mode = dev->d[14];
154+ console_start_fork_pipe(dev);
155+}
156+
157+static void close_console(Device*dev) {
158+ console_kill_child(dev);
159+}
160+
161+static Uint8 subprocess_console_in(Device*dev,Uint8 id) {
162+ switch(id) {
163+ case 5: case 6: console_check_child(dev); break;
164+ }
165+ return dev->d[id];
166+}
167+
168+// End of subprocess support
169+
170 static void console_out(Device*dev,Uint8 id) {
171 switch(id) {
172 case 8: fputc(dev->d[8],outf); break;
173 case 9: fputc(dev->d[9],stderr); break;
174+ // Subprocess
175+ case 15: if(enable_subprocess) console_start_fork(dev); break;
176 }
177 }
178
179@@ -895,6 +1055,7 @@ static void run_audio(void) {
180 static void do_extension_by_uuid(Uint16 addr) {
181 static const Uint8 uuid_8color[]="\x80\x17\x51\x32\xE2\x63\x11\xED\xB8\xC9\x00\x26\x18\x74\x54\x16";
182 static const Uint8 uuid_screencompat[]="\x97\x0B\x5A\x0C\x2C\x44\x11\xEE\xAC\x3B\x00\x26\x18\x74\x54\x16";
183+ static const Uint8 uuid_subprocess[]="\x9C\x5F\x13\x56\x6B\xC5\x11\xEF\xA6\xC9\x00\x26\x18\x74\x54\x16";
184 int i;
185 if(mem[addr+1]==0x00 && use_screen && !memcmp(mem+addr+2,uuid_8color,16)) {
186 for(i=0;i<8;i++) {
187@@ -911,6 +1072,9 @@ static void do_extension_by_uuid(Uint16 addr) {
188 screencompat=mem[addr+19];
189 blend[0][0]=(screencompat&0x01?4:0);
190 mem[addr+18]=1;
191+ } else if(mem[addr+1]==0x10 && use_thread && use_console && allow_write && !memcmp(mem+addr+2,uuid_subprocess,16)) {
192+ device[1].in=subprocess_console_in;
193+ enable_subprocess=mem[addr+18]=1;
194 }
195 }
196