Mon 16 Mar 11:09:06 CET 2026
This commit is contained in:
parent
e9a642eb1b
commit
3725ba9c13
477
src/unix.c
Normal file
477
src/unix.c
Normal file
|
|
@ -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 <sys/select.h>
|
||||||
|
#include "debug.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
#define __stack_t_defined 1
|
||||||
|
#include <time.h> /* for timer functions and itimerspec */
|
||||||
|
#include <signal.h> /* for sigaction */
|
||||||
|
#include <errno.h> /* for errno */
|
||||||
|
|
||||||
|
#include "net.h"
|
||||||
|
#include <poll.h>
|
||||||
|
|
||||||
|
|
||||||
|
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<NUMPORTS;i++) {
|
||||||
|
if (portfilerd[i]) {
|
||||||
|
mkfifo(portfilerd[i],0666);
|
||||||
|
portfdrd[i]=open(portfilerd[i], O_RDONLY|O_NONBLOCK);
|
||||||
|
if (portfdrd[i] < 0) {
|
||||||
|
perror("open portrd");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
portfds[i].fd=portfdrd[i];
|
||||||
|
portfds[i].events=POLLIN|POLLHUP;
|
||||||
|
nportfds++;
|
||||||
|
log(LOGINFO,"Read port fifo %s opened (%d).\n",portfilerd[i],portfdrd[i]);
|
||||||
|
#if HAS_NET_ROUTING > 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;i<NUMPORTS;i++) {
|
||||||
|
if (portfilerd[i]) {
|
||||||
|
// close(portfdrd[i]);
|
||||||
|
unlink(portfilerd[i]);
|
||||||
|
portfds[i].fd=0;
|
||||||
|
portfds[i].events=0;
|
||||||
|
if (verbose) printf("Read port fifo %s removed (%d).\n",portfilerd[i],portfdrd[i]);
|
||||||
|
// TODO fd not valid anymore?
|
||||||
|
}
|
||||||
|
if (portfilewr[i]) {
|
||||||
|
// close(portfdwr[i]);
|
||||||
|
unlink(portfilewr[i]);
|
||||||
|
if (verbose) printf("Write port fifo %s removed (%d).\n",portfilewr[i],portfdwr[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int __dso_handle;
|
||||||
|
|
||||||
|
void sigterm_handler() {
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ioinit() {
|
||||||
|
nportfds=0;
|
||||||
|
for(int i=0;i<NUMPORTS;i++) {
|
||||||
|
portfdrd[i]=portfdwr[i]=-1;
|
||||||
|
portfilerd[i]=portfilewr[i]=NULL;
|
||||||
|
}
|
||||||
|
atexit(port_close);
|
||||||
|
signal(SIGTERM, sigterm_handler);
|
||||||
|
signal(SIGINT, sigterm_handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Wait or check (nonblock=1) for IO and timeout events
|
||||||
|
returns -1 if interrupted an nothing to run, else 0
|
||||||
|
*/
|
||||||
|
int iowait(context_t *C, int nonblock) {
|
||||||
|
int status=0,timeout=0;
|
||||||
|
context_t *c;
|
||||||
|
reg_t *R;
|
||||||
|
c=C;
|
||||||
|
while (c) {
|
||||||
|
// compute next pending timeout for contexts
|
||||||
|
R=c->R;
|
||||||
|
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<NUMPORTS;i++) {
|
||||||
|
if (portfds[i].revents&POLLHUP) {
|
||||||
|
// hang up of other side, reopen port
|
||||||
|
port_reopen(i,'r');
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
#if HAS_NET_ROUTING > 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Loading…
Reference in New Issue
Block a user