diff --git a/src/unix.c b/src/unix.c new file mode 100644 index 0000000..94056c0 --- /dev/null +++ b/src/unix.c @@ -0,0 +1,477 @@ +#include "config.h" +#include "types.h" +#include "lexer.h" +#include "tokens.h" +#include "mem.h" +#include "reg.h" +#include "stack.h" +#include "context.h" +#include "ops.h" +#include "code.h" +#include "vm.h" +#include "var.h" +#include "printf.h" +#include "ccall.h" +#include "event.h" +#include "context.h" +#include "version.h" +#include "unix.h" +#include "utils.h" +#include +#include "debug.h" +#include "log.h" +#include +#include +#include + +#include +#include +#include +#include +#include + +#define __stack_t_defined 1 +#include /* for timer functions and itimerspec */ +#include /* for sigaction */ +#include /* for errno */ + +#include "net.h" +#include + + +extern int verbose; + +/* Makes the given file descriptor non-blocking. + * Returns 1 on success, 0 on failure. +*/ +int fd_make_blocking(int fd) +{ + int flags; + flags = fcntl(fd, F_GETFL, 0); + if(flags == -1) /* Failed? */ + return 0; + /* Clear the blocking flag. */ + flags &= ~O_NONBLOCK; + return fcntl(fd, F_SETFL, flags) != -1; +} + + +/* + ============== + IO Multiplexer + ============== + Low-level IO via file descriptors (fd>=0) by net module or host application + High-level IO via ports from VM and PLX IO operations !? (fd<0) +*/ +int availbyte(int fd) { + if (fd>=0) { + // real fd + struct pollfd pfd; + pfd.fd=fd; + pfd.events=POLLIN; + poll(&pfd,1,0); + return pfd.revents&POLLIN?1:0; + } else { + fd=-fd-1; +#if HAS_NET > 0 +#if HAS_NET_ROUTING > 0 + +#else /* HAS_NET_ROUTING=0 */ + if (Port && (fd==0 || fd==1000)) { + // Port 0 + return PortAvailByte(0); + } +#endif +#else /* HAS_NET=0 */ +#endif + if (fd==0) { + struct pollfd pfd; + pfd.fd=fd; + pfd.events=POLLIN; + poll(&pfd,1,0); + return pfd.revents&POLLIN?1:0; + } + return 0; + } +}; +char inbyte(int fd) { + char buf=0; + if (fd>=0) { + read(fd,&buf,1); + return buf; + } else { + fd=-fd-1; +#if HAS_NET > 0 +#if HAS_NET_ROUTING > 0 + +#else /* HAS_NET_ROUTING=0 */ + if (Port && (fd==0 || fd==1000)) { + // Port 0 + return PortInByte(0); + } +#endif +#else /* HAS_NET=0 */ +#endif + if (fd==0) return getchar(); + return 0; + } +}; +int outbyte(int fd,char x) { + if (fd>=0) { + return write(fd,&x,1); + } else { + fd=-fd-1; +#if HAS_NET > 0 +#if HAS_NET_ROUTING > 0 + +#else /* HAS_NET_ROUTING=0 */ + if (Port && (fd==1 || fd==1000)) { + // Port 0 + return PortOutByte(0,x); + } +#endif +#else /* HAS_NET=0 */ +#endif + if (fd==1) putchar(x); + return -1; + } +}; + + + + +extern int verbose; +#if HAS_NET > 0 +/* + Under UNIX we use named FS FIFOs for node-node communication. + The FIFOs are connected to links. +*/ +static int portfdrd[NUMPORTS]; +static int portfdwr[NUMPORTS]; +char *portfilerd[NUMPORTS]; +char *portfilewr[NUMPORTS]; +static struct pollfd portfds[NUMPORTS]; // currently only rx monitors +static int nportfds; // number of polled (rx) fds + +/* + Open all registered fifo ports +*/ + +int port_open() { + for(int i=0;i 0 + Ports[i]->rd=portfdrd[i]; + Ports[i]->state=LSTART; +#else + Port->rd=portfdrd[i]; + Port->rxState=LSTART; +#endif + } + if (portfilewr[i]) { + mkfifo(portfilewr[i],0666); + portfdwr[i]=open(portfilewr[i], O_RDWR); + if (portfdwr[i] < 0) { + perror("open portwr"); + exit(1); + } + log(LOGINFO,"Write port fifo %s opened (%d).\n",portfilewr[i],portfdwr[i]); +#if HAS_NET_ROUTING > 0 + Ports[i]->wr=portfdwr[i]; +#else + Port->wr=portfdwr[i]; +#endif + } + } +} + +/* + Got HUP from other side, reopen port fifo +*/ +int port_reopen(int portindex, char dir) { + if (dir=='r' && portfilerd[portindex]) { + close(portfdrd[portindex]); + portfdrd[portindex]=open(portfilerd[portindex], O_RDONLY|O_NONBLOCK); + if (portfdrd[portindex] < 0) { + perror("reopen portrd"); + exit(1); + } + log(LOGINFO,"Read port fifo %s reopened (%d).\n",portfilerd[portindex],portfdrd[portindex]); + portfds[portindex].fd=portfdrd[portindex]; + portfds[portindex].events=POLLIN|POLLHUP; + } + if (dir=='w' && portfilewr[portindex]) { + close(portfdwr[portindex]); + portfdwr[portindex]=open(portfilewr[portindex], O_RDWR); + if (portfdwr[portindex] < 0) { + perror("reopen portwr"); + exit(1); + } + log(LOGINFO,"Write port fifo %s reopened (%d).\n",portfilewr[portindex],portfdwr[portindex]); + } +} + + +/* + Close all opened ports (on exit) +*/ +void port_close(void) { + if (verbose) printf("closing ...\n"); + for(int i=0;iR; + if (R->state&PTIMEOUT) { + // delay + int milliseconds=R->timeout-MILLIS(); + if (milliseconds<=0) { + // timeout exhausted + HandleTimeout(c); + return 0; + } else { + if (!timeout) timeout = milliseconds; + timeout=MIN(timeout,milliseconds); + } + } + c=c->next; + } +#if DEBUG > 0 + log(LOGDEBUG2,"iowait timeout=%d ms nportfds=%d nonblock=%d\n",timeout,nportfds,nonblock); +#endif + + int n=poll(portfds,nportfds,timeout==0?(nonblock?0:-1):timeout); + if (n<0 && errno==EINTR) { + // Interrupt + c=C; + while (c) { + R=c->R; + if (RUNNABLE(R)) { +#if DEBUG > 0 + log(LOGDEBUG2,"iowait (poll=%d) interrupted, returns %d (C#%d) (timeout=%d)\n", + n,1,CONTEXTID(c), + timeout); +#endif + return 1; // interrupted for event handling + } + c=c->next; + } +#if DEBUG > 0 + log(LOGDEBUG2,"iowait (poll=%d) interrupted, returns %d (no runnable C) (timeout=%d)\n", + n,-1, + timeout); +#endif + return -1; // interrupted by other reason + } + if (n>0) { + // IO ready or HUP, handle IO, basically net messages + status=0; +#if HAS_NET > 0 + for(int i=0;i 0 + if (portfds[i].revents&POLLIN && Ports[i]->state==LSTART) { + PortReceiver(Ports[i]); +#else + if (portfds[i].revents&POLLIN && Port->rxState==LSTART) { + PortReceiver(); +#endif + } + } +#endif + } else if (timeout) { + // Timeout + c=C; + status = 0; + while (c) { + status = status || HandleTimeout(c); + c=c->next; + } + } +#if DEBUG > 0 + log(LOGDEBUG2,"iowait (poll=%d) status=%d\n",n,status); +#endif + return status; +} + +/* + Timer service control +*/ + + +static timer_t timer1,timer2; +static struct sigaction timer1_sigact,timer2_sigact; +static struct sigevent timer1_sigevt,timer2_sigevt; + + + +static void timer_signal_handler(int signum, siginfo_t *info, void *context) +{ + int timernum=signum-SIGRTMIN; +#if DEBUG>0 + log(LOGDEBUG2,"Timer[%d] interrupt, raising event\n",timernum); +#endif + RaiseEvent("timer",timernum); +} + +int timer_init() { + /* setting signal and its handler */ + sigemptyset(&timer1_sigact.sa_mask); + sigemptyset(&timer2_sigact.sa_mask); + timer1_sigact.sa_sigaction = timer_signal_handler; + timer2_sigact.sa_sigaction = timer_signal_handler; + timer1_sigact.sa_flags = SA_SIGINFO; + timer2_sigact.sa_flags = SA_SIGINFO; + if (sigaction(SIGRTMIN+0, &timer1_sigact, NULL)) + return errno; + if (sigaction(SIGRTMIN+1, &timer2_sigact, NULL)) + return errno; + + /* setting timer event */ + timer1_sigevt.sigev_notify = SIGEV_SIGNAL; + timer1_sigevt.sigev_signo = SIGRTMIN+0; + timer1_sigevt.sigev_value.sival_ptr = NULL; + timer2_sigevt.sigev_notify = SIGEV_SIGNAL; + timer2_sigevt.sigev_signo = SIGRTMIN+1; + timer2_sigevt.sigev_value.sival_ptr = NULL; + + if (timer_create(CLOCK_REALTIME, &timer1_sigevt, &timer1)) + return errno; + if (timer_create(CLOCK_REALTIME, &timer2_sigevt, &timer2)) + return errno; + return 0; +} + +int timer_start(int index, int millis) { + /* setting alarm time */ +#if DEBUG>0 + log(LOGDEBUG2,"Timer[%d] start %d ms\n",index,millis); +#endif + struct itimerspec alarm; + alarm.it_value.tv_sec = millis/1000; + alarm.it_value.tv_nsec = (millis-alarm.it_value.tv_sec*1000)*1000000L; + alarm.it_interval.tv_sec = alarm.it_value.tv_sec; + alarm.it_interval.tv_nsec = alarm.it_value.tv_nsec; + + /* starting timer */ + switch (index) { + case 0: + if (timer_settime(timer1, 0, &alarm, NULL)) + return errno; + break; + case 1: + if (timer_settime(timer2, 0, &alarm, NULL)) + return errno; + break; + } + return 0; +} +int timer_stop(int index) { + /* setting alarm time */ +#if DEBUG>0 + log(LOGDEBUG2,"Timer[%d] stop\n",index); +#endif + struct itimerspec alarm; + alarm.it_value.tv_sec = 0L; + alarm.it_value.tv_nsec = 0L; + alarm.it_interval.tv_sec = 0L; + alarm.it_interval.tv_nsec = 0L; + + /* starting timer */ + switch (index) { + case 0: + if (timer_settime(timer1, 0, &alarm, NULL)) + return errno; + break; + case 1: + if (timer_settime(timer2, 0, &alarm, NULL)) + return errno; + break; + } + return 0; +} + +void interrupt() { + +} + +char* readFile(char *path) { + FILE *f = fopen(path, "rb"); + fseek(f, 0, SEEK_END); + long fsize = ftell(f); + fseek(f, 0, SEEK_SET); /* same as rewind(f); */ + char *string = malloc(fsize + 1); + fread(string, fsize, 1, f); + fclose(f); + string[fsize] = 0; + return string; +} + + +// always directed to stdout +void vLog(const char* fmtStr, ...) { + va_list va; + va_start(va, fmtStr); + vfprintf(stdout, fmtStr, va); + fflush(stdout); + va_end(va); +} + + +