/* * ex_async - an example program showing how asynchronous I/O * can be performed from a user-level task. * J. M. Barton 2/25/89 * * This program is herewith released to the public domain. You may do * as you wish with this code. The author (J. M. Barton) and his * employer (Silicon Graphics, Incorporated) assume no liability of any * kind in connection with the use or non-use of this code or any fragment * of it. Use at your own risk. Please retain this statement with all * copies or fragments of code taken from this program. */ # include <sys/types.h> # include <sys/prctl.h> # include <sys/schedctl.h> # include <termio.h> # include <signal.h> # include <stdio.h> # define COMSIG SIGUSR1 # define RTPRI NDPHIMAX /* * Example strategy is to start a slave reading from the keyboard, and it * will signal the parent whenever a character is read, and the parent grabs * the character and echo's it, and then starts the child waiting again. * Program will work passing any file through on it's standard input, though. */ struct { /* structure we communicate through */ int ppid; /* parent process ID */ int cpid; /* child process ID */ int fd; /* file descriptor to read */ char byte; /* acquired byte */ } comarea; struct termio tb; /* original TTY state */ main() { int asyncslave(); int asyncintr(); int ttyclean(); struct termio ta; /* * Just for fun, start the slave first. He will block himself. */ comarea.ppid = getpid(); comarea.cpid = sproc(asyncslave, PR_SALL, 0); /* * Set up the terminal to return a single byte at a time. */ if (ioctl(0, TCGETA, &tb) != -1) { signal(SIGINT, ttyclean); ta = tb; ta.c_line = 0; ta.c_iflag = BRKINT|ICRNL; ta.c_lflag &= ~(ICANON|ECHO); ta.c_cc[VMIN] = 1; ta.c_cc[VTIME] = 0; ioctl(0, TCSETA, &ta); } /* * Note that we can change the file descriptor at any time, such * as opening a new file, and pass that to the child. The sproc() * facility insures that the child has exactly the same file * descriptors as the parent. */ comarea.fd = 0; /* * Set up the interrupt handler and let the slave go. */ sigset(COMSIG, asyncintr); sigrelse(COMSIG); unblockproc(comarea.cpid); /* * Now just wait for the slave to read a character and then output * it. */ sieve(); /*NOTREACHED*/ } /* * On interrupt, output the character that was read. */ asyncintr() { putchar(comarea.byte); unblockproc(comarea.cpid); } /* * Loop forever reading characters from the input port and passing them * to the master. */ asyncslave() { /* * Put us at the highest possible real-time priority so * we respond to events very quickly. */ schedctl(NDPRI, 0, RTPRI); for (;;) { /* * Wait for command to read and do the read. This simple * protocol insures that we never trash the communications * buffer. */ blockproc(0); if (read(comarea.fd, &comarea.byte, sizeof(char)) != 1) { /* * Error reading from the descriptor. Sink * the parent. */ kill(comarea.ppid, SIGINT); exit(1); } /* * Signal the parent that we got a valid byte. */ kill(comarea.ppid, COMSIG); } /*NOTREACHED*/ } /* * Function to burn up time - sieve. */ # define true 1 # define false 0 # define size (256*1024) # define sizep1 (size+1) sieve() { register int i,prime,k,count,iter; char flags[sizep1]; for (iter = 0;; iter++) { count=0; for(i = 0; i <= size;i ++) flags[i] = true; for(i = 0;i <= size;i ++) { if(flags[i]) { prime = i + i + 3; k = i + prime; while(k <= size) { flags[k] = false; k += prime; } count = count + 1; } } /* * Gaurantee that characters read from the keyboard don't * mess up our output. */ sighold(COMSIG); printf("."); fflush(stdout); sigrelse(COMSIG); } /*NOTREACHED*/ } /* * Clean up if we were attached to a tty. */ ttyclean() { ioctl(0, TCSETA, &tb); exit(1); }