+#define _XOPEN_SOURCE 600
#include <fcntl.h>
#include <poll.h>
+#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/wait.h>
#include <termios.h>
#include <unistd.h>
#include <SDL2/SDL.h>
#define WINDOW_WIDTH (PADDED_WIDTH * WINDOW_X_SCALE)
#define WINDOW_HEIGHT (PADDED_HEIGHT * WINDOW_Y_SCALE)
-#define INSTRS_PER_UPDATE 1500
+#define INSTRS_PER_UPDATE 15000
#define IO_PAGE 0xc000
#define IO_KBD 0xc000
#define TRACE 0
+extern char **environ;
+
+int fd_in = STDIN_FILENO;
+int fd_out = STDOUT_FILENO;
+int child_pid;
struct termios termios_attr;
SDL_Window *window;
case STDIN_DATA:
{
uint8_t data = 'X' - 0x40;
- ssize_t count = read(STDIN_FILENO, &data, 1);
+ ssize_t count = read(fd_in, &data, 1);
if (count == -1) {
perror("read()");
exit(EXIT_FAILURE);
}
case STDIN_STATUS:
{
- struct pollfd fd = {STDIN_FILENO, POLLIN | POLLPRI, 0};
+ struct pollfd fd = {fd_in, POLLIN | POLLPRI, 0};
if (poll(&fd, 1, 0) == -1) {
perror("poll()");
exit(EXIT_FAILURE);
}
case STDOUT_STATUS:
{
- struct pollfd fd = {STDOUT_FILENO, POLLOUT, 0};
+ struct pollfd fd = {fd_out, POLLOUT, 0};
if (poll(&fd, 1, 0) == -1) {
perror("poll()");
exit(EXIT_FAILURE);
hires = APPLE_HIRES1;
break;
case STDOUT_DATA:
- if (write(STDOUT_FILENO, &val, 1) == -1) {
+ if (write(fd_out, &val, 1) == -1) {
perror("write()");
exit(EXIT_FAILURE);
}
}
}
+void sigchld_handler(int signum) {
+ if (child_pid == 0) {
+ fprintf(stderr, "SIGCHLD: no child process yet\n");
+ exit(EXIT_FAILURE);
+ }
+
+ int wstatus;
+ if (waitpid(child_pid, &wstatus, WNOHANG) == -1) {
+ perror("waitpid()");
+ exit(EXIT_FAILURE);
+ }
+
+ if (!WIFEXITED(wstatus)) {
+ fprintf(stderr, "SIGCHLD: child process was killed\n");
+ exit(EXIT_FAILURE);
+ }
+
+ // reflect child's exit status to parent
+ //fprintf(stderr, "SIGCHLD: child exit status %d\n", WEXITSTATUS(wstatus));
+ exit(WEXITSTATUS(wstatus));
+}
+
void termios_atexit(void) {
- if (tcsetattr(STDIN_FILENO, TCSADRAIN, &termios_attr) == -1)
+ if (tcsetattr(fd_in, TCSADRAIN, &termios_attr) == -1)
perror("tcsetattr()");
}
}
if (argn >= argc) {
- printf("usage: %s [-t] program.bin\n", argv[0]);
+ printf("usage: %s [-t] [utility.obj ...] program.obj [-- child_executable [child_argument ...]]\n", argv[0]);
exit(EXIT_FAILURE);
}
int load_address = 0;
- while (argn < argc)
- load_address = bload(argv[argn++]);
+ while (argn < argc) {
+ char *p = argv[argn++];
+ if (strcmp(p, "--") == 0)
+ break;
+ load_address = bload(p);
+ }
+
+ // open pty and child process if requested
+ if (argn < argc) {
+ int fd_master = posix_openpt(O_RDWR);
+ if (fd_master == -1) {
+ perror("posix_openpt()");
+ exit(EXIT_FAILURE);
+ }
+
+ if (grantpt(fd_master) == -1) {
+ perror("grantpt()");
+ exit(EXIT_FAILURE);
+ }
+
+ if (unlockpt(fd_master) == -1) {
+ perror("unlockpt()");
+ exit(EXIT_FAILURE);
+ }
+
+ // Open the slave side ot the PTY
+ int fd_slave;
+ {
+ char *p = ptsname(fd_master);
+ fd_slave = open(p, O_RDWR);
+ if (fd_slave == -1) {
+ perror(p);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ signal(SIGCHLD, sigchld_handler);
+ child_pid = fork();
+ if (child_pid == 0) {
+ dup2(fd_slave, STDIN_FILENO);
+ dup2(fd_slave, STDOUT_FILENO);
+ dup2(fd_slave, STDERR_FILENO);
+
+ int n = argc - argn;
+ char **p = malloc((n + 1) * sizeof(char *));
+ memcpy(p, argv + argn, n * sizeof(char *));
+ p[n] = NULL;
+ execve(argv[argn], p, environ);
+
+ perror(argv[argn]);
+ exit(EXIT_FAILURE);
+ }
+
+ fd_in = fd_master;
+ fd_out = fd_master;
+ close(fd_slave);
+ }
// do this before creating the CPU
mem[RESET_VECTOR] = (uint8_t)(load_address & 0xff);
mem[RESET_VECTOR + 1] = (uint8_t)(load_address >> 8);
- if (isatty(STDIN_FILENO)) {
- if (tcgetattr(STDIN_FILENO, &termios_attr) == -1) {
+ if (isatty(fd_in)) {
+ if (tcgetattr(fd_in, &termios_attr) == -1) {
perror("tcgetattr()");
exit(EXIT_FAILURE);
}
attr.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
attr.c_cc[VMIN] = 1;
attr.c_cc[VTIME] = 0;
- if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &attr) == -1) {
+ if (tcsetattr(fd_in, TCSAFLUSH, &attr) == -1) {
perror("tcsetattr()");
exit(EXIT_FAILURE);
}
if (usleep_count) {
#if 1 // hack to avoid lagginess in ribbit game
- struct pollfd fd = {STDIN_FILENO, POLLIN | POLLPRI, 0};
+ struct pollfd fd = {fd_in, POLLIN | POLLPRI, 0};
if (poll(&fd, 1, (usleep_count + 999) / 1000) == -1) {
perror("poll()");
exit(EXIT_FAILURE);