raveling@vaxb.isi.edu (Paul Raveling) (01/19/89)
In article <2766@ficc.uu.net> peter@ficc.uu.net (Peter da Silva) writes: > >Perhaps a standard set of real-time calls can be decided on. A set more >suited to a wider variety of operating systems. Something like: > > token = start_read(fd, buffer, nbytes, timeout); > ... > nread = check_io(token); > ... > nread = wait_io(token); Here's a C rendition of what we did in several systems starting in 1972 that directly addresses this; I'd still recommend something like: #define ANYEVENT 0 #define READ_EVENT_ID xxx /* integer values to uniquely */ #define TIMEOUT_EVENT_ID xxx /* identify events */ struct event_data {...} evdata; /* Generic event data structure */ ... ... ARead (file, &buffer, nbytes, READ_EVENT_ID); SetTimer (timeout, TIMEOUT_EVENT_ID); ... ... evdata = WaitFor (ANYEVENT); /* Or if you prefer, WaitFor (READ_EVENT_ID) or WaitFor (READ_EVENT_ID "|" TIMEOUT_EVENT_ID) or CheckFor (whatever) [don't block] */ switch ( evdata.event_id ) { case READ_EVENT_ID: completion_status = evdata.status; byte_count = evdata.byte_count; ... case TIMEOUT_EVENT_ID: ... } Communicating event data was the basis for scheduling processes in these systems; this proved to be an extremely general mechanism that made it easy to program a LARGE variety of functions using cooperating processes. It was also quite fast: In communicating small amounts of info, such as i/o request or i/o completion parameters, and doing the consequent context switch, the 1975 system (EPOS) was about 10-12 times faster than UNIX V6. --------------------- Paul Raveling Raveling@vaxb.isi.edu
peter@ficc.uu.net (Peter da Silva) (01/24/89)
In article <7304@venera.isi.edu>, raveling@vaxb.isi.edu (Paul Raveling) writes: > In article <2766@ficc.uu.net> peter@ficc.uu.net (Peter da Silva) writes: > >Perhaps a standard set of real-time calls can be decided on. A set more > >suited to a wider variety of operating systems. Something like: > > token = start_read(fd, buffer, nbytes, timeout); ... > > nread = check_io(token); ... > > nread = wait_io(token); > Here's a C rendition of what we did in several systems > starting in 1972 that directly addresses this; I'd still > recommend something like: > ARead (file, &buffer, nbytes, READ_EVENT_ID); > SetTimer (timeout, TIMEOUT_EVENT_ID); I like it too. Silly me. Of course you want to do it this way. One thing, though... passing structures around isn't so cool. And some way of allocating an event flag dynamically (so you can use this stuff in libs) is useful. In AmigaDOS you call AllocSignal(MASK) to do this, but it's more UNIXy to use a file descriptor, or habe the call return the event flag... revent = aread(fd, buffer, nbytes); tevent = asleep(timeout); mask = await(revent|tevent); if(!(mask & revent)) akill(revent); akill(tevent); nread = astatus(revent); And, what's more, you have the kernel of a better error handling setup than perror... -- Peter da Silva, Xenix Support, Ferranti International Controls Corporation. Work: uunet.uu.net!ficc!peter, peter@ficc.uu.net, +1 713 274 5180. `-_-' Home: bigtex!texbell!sugar!peter, peter@sugar.uu.net. 'U` Opinions may not represent the policies of FICC or the Xenix Support group.
raveling@vaxb.isi.edu (Paul Raveling) (02/01/89)
In article <2851@ficc.uu.net> peter@ficc.uu.net (Peter da Silva) writes: > >One thing, though... passing structures around isn't so cool. I agree within this context (oops, I already edited that part of the message out), though I have actually done this on occasion. What I'd REALLY like is a language feature for multiple return values... it might look something like: (completion_status, bytes_actually_read, updated_buffer_pointer) = Read (file, buffer, nbytes); ** or ** WaitFor (READ_EVENT_ID /* for prior ARead */); In fact, that example is what we did in EPOS for block input, where we roughly mimiced TENEX's SIN (string input) function. The catch was that we did it in assembly language. It turns out that sensible machine designers provided a great feature to help with this sort of thing -- a register set. On a decent machine there are at least as many registers as there are parameters for functions such as this, and returned info is an even easier fit. Using the registers is fast, no memory allocation is needed for parameters in registers, and the hardware supplies stack operations to save and restore them on opposite sides of context switches. With multiple return values it's easier to avoid overloaded return values. With a separate status code and count of bytes read, there's no need for special cases such as byte counts or "character" values of -1 or 0. In EPOS virtually ALL system calls issued a status (return) code that the caller could feed to a function something like perror; 0 was the universal code for "no error". It's possible to do this sort of thing in a fairly C-like language. BLISS-11 even did a good job of handling parameters in registers. Seems like it would be both fun and valuable to fuse some of these notions for languages and system interfaces into a coherent scheme. --------------------- Paul Raveling Raveling@vaxb.isi.edu