Xref: utzoo comp.lang.c:8176 comp.unix.questions:6070 comp.unix.wizards:7058 Path: utzoo!mnetor!uunet!husc6!ut-sally!utah-cs!utah-gr!uplherc!sp7040!wsccs!terry From: terry@wsccs.UUCP (terry) Newsgroups: comp.lang.c,comp.unix.questions,comp.unix.wizards Subject: keypressed()--- and the answer is: Message-ID: <303@wsccs.UUCP> Date: 12 Mar 88 08:34:57 GMT References: <136@forty2.UUCP> <3961@galbp.LBP.HARRIS.COM> Lines: 126 Summary: LONG. Read only if you have an interest in I/O. In article <3961@galbp.LBP.HARRIS.COM>, phil@galbp.LBP.HARRIS.COM (Phil McDonald) writes: > In article <136@forty2.UUCP> eschle@forty2.UUCP (Patrik Eschle) writes: > >How do I write a function keypressed(), that returns 0 if no > >char is in the input queue and returns the character otherwise? > >Keypressed() should not block, and should leave the terminal in its > >initial state after returning. > > > >I can't use curses and have played around with ioctl, but its > >really slow. > > > >Any suggestions? Patrik > > =========================================================================== > I would suggest using the rdchk(s) command. Phil, read the summary line. I will assume you are using a UNIX machine, since you mentioned ioctl and you didn't specify otherwise. It isn't fast, probably because 1) Your machine isn't fast or 2) You are using a DMA I/O controller or 3) You are calling it wrong There are at least 3 ways to do it and not get into too much trouble: 1) This one's breif, so here's a code fragment: #include #include /* * r e a d c h k ( ) * * returns number of characters pendinding input on an 'open()'ed * tty. */ readchk( fd) int fd; { int cnt; ioctl( fd, FIONREAD, &cnt); return( cnt); } 2) This isn't breif, so implimentation is left up to the student: A. Define a shared memory segment. B. Make sure the shared memory segment has room for 2 characters. C. Zero the first character. D. Fork a child process to hang on a single character read. E. When the read completes, the child process puts the character into the second character position of the shared memory, then sets the first to one. F. The child process buzz-loops on the first character position, and loops back up to the 'hang-on-read' when the first character is returned to zero. meanwhile... G. The main program occasionally looks at the first character. H. When the first character is non-zero, it moves the second to a local buffer, then zeroes it. 3) Same as #2, except the child process is another program, which is popen()'ed. Instead of a fork, a popen( "program", "r") is done, where the purpose of the child is to hang on the read and signal the parent (via a signal, semaphore, or shared memory) when the read completes, then the child writes the character read to the pipe. A better method whold be to write the character to the pipe first. When the parent realizes that a character there, via whatever method, it reads *from the pipe* the character read by the child. All of the methods described above are not the fastest, but they will work. Which one you should use depends on your situation, and your operating system. The readchk() suggested by Phil basically *DOES* what is done in method 1, with the exception that it only works on fd 0 (stdin). Which one you use depends on your application and the system you are on. If you are on a small system (like a 386 box), you are probably not going to get -----f-a-s-t--->->-> results, no matter what you do. If you are using a DMA device, polling via method #1 or rdchk() is not happy, as it causes I/O to occur, and this (naturally) must occur through a DMA channel. DMA channels do not like small I/O like this, and they will fight it by waiting for 1) a full DMA 'packet' (simplified terminology) or 2) a timeout if there are not enough I/O operations to 'fill' a 'packet'. This is so they can avoid causing too many interrupts, as the whole purpose of a DMA device is to offload processor I/O work so that instead of getting an interrupt for each character, you get one for each 'bunch' of characters. Some systems do NOT support semaphores, or support them such that you wouldn't want to use them, even if you trusted them, which you don't. The same goes for shared memory. Signals are reliable, but can be slow, depending on the kernal implimentation. The main problem with BOTH 2 & 3 are that you are giving the system the opportunity to swap out one process while the other one does it's stuff. If you are on a small system, it's probably dying because you are being swapped out on your ioctl() (remember that on almost _every_ kernal call, you are opening yourself up to be swapped, _especially_ I/O operations. What it boils down to is that I really don't have enough info to give you a cut and dry answer. What UNIX are you running on? What box? Is it using DMA I/O? What is the application? If you could say something like 'I am running on a VAX 750 under Berkley 4.2 and writing a Kermit connect mode to go over DMA dhv11 controllers', then I would say that you should use the selectio() function (a Berkley exclusive) which would wait for a read to complete on 2 fd's, thereby allowing you to 'queue' your reads, sort of... whichever completed, you'd go off and do something, then you'd re-queue. If you email me more info, I will email you an answer. Be sure to provide adequate references, please, including a return path.. Flame at will. I have working code for all the above, and I *love* it when someone sticks their foot in their mouth so I can give compileable examples of why they are a fool. :-) | Terry Lambert UUCP: ...!decvax!utah-cs!century!terry | | @ Century Software or : ...utah-cs!uplherc!sp7040!obie!wsccs!terry | | SLC, Utah | | These opinions are not my companies, but if you find them | | useful, send a $20.00 donation to Brisbane Australia... | | 'There are monkey boys in the facility. Do not be alarmed; you are secure' |