This document covers details of the chex (cheops execute) utility used for executing Cheops programs. It provides an overview of how chex downloads a program and then communicates with it using Magic Seven's interprocess communications facilities to provide myriad services on the host platform. All services that chex provides to the client program are then reviewed including: standard UNIX system calls and file I/O, blocked and non-blocked massive data transfers, communications and control, redirection of standard I/O, conventional datfile library support, and Cheops specific extensions to the datfile library.
For a basic understanding of how to use chex, see Chex Usage.
Chex uses the basic client-server model (see Magic7 IPC System) to handle all the communication between the application program and itself. Chex plays the part of the host server, handling requests given to it by the local client application program being executed on Cheops. When chex is called from the host machine to execute a Cheops program, it creates a service port that allows message passing between it and its client, allocates space in Cheops local memory for the programs text, data and stack, fixes the program's relative addresses to the given, loads the program's sections into the appropriate addresses, and informs the Magic7 (M7) operating system to start a new process with given path name, command line parameters, and address space.
Having started execution of the local client program, chex then waits in a tight infinite loop, expecting to service messages that come from it.When the local client makes a system call, the call is trapped by the M7 operating system. M7 prepares a request message which it sends to the service port used to communicate to the chex server. Chex notices the request, takes the message off the message queue, interprets the request and services requested UNIX system call. Upon completion, the system call's return value is put into into a response message and is sent back to the client via the service port. M7 immediately recognizes the response, takes it off the message queue, parses off the return value, and returns it to the calling application.
Cheops does not have a file system, but a Cheops client program can request that chex do file system calls in its behalf, and then return the results. The following standard UNIX file system calls are currently supported by Magic7 and chex if your local program links the Cheops library (denoted as -L$CHEOPS_LOCAL_LIB -lcheops in your Makefile).
Since the functions are standard, you need not include any special
files to get their prototypes -- just the standard UNIX include files
like stdlib.h (found by the compiler at -I${G960INC} ) to get
prototypes for these functions:
open(), close(), read(), write(), create(), lseek(), unlink(),
access(), system(), umask(), exit()
System call handling normally requires very little message passing overhead since parameters and return values are only a few bytes. System calls that require massive data transfers, such as read() and write(), cannot be handled by sending messages to the service port, but rather are handled as a separate high speed host/Cheops data transfer. When the transfer has completed, the return value of the system call is then returned in the normal message passed manner.
All standard system calls are supported in the typical remote
procedure call fashion. That is, the caller blocks until the remote
handler completes the request. This blocking approach to handling
massive data transfers is clearly non-optimal when we consider that we
have two different processes (the host server and the local client)
which are running on different processors (the host platform and
Cheops). To circumvent this shortcoming, Chex supports semaphored data
transfer operations for its local client:
future_read()
future_write()
These functions take the same parameters as read and write, with an additional semaphore (refer to Magic Seven IPC System) that should be set when the call is made. No response from chex is required, so these functions return to the calling local client immediately, so it can go on to other tasks. Meanwhile, chex has begun servicing the massive data transfer via high speed SCSI transfer. Because data transfers from/to host memory to/from Cheops memory via SCSI is handled by a separate DMA controller, the clients program execution is not blocked and we can achieve true multiprocessing. When chex has completed the request, it clears the given semaphore, which acts as a signal to the calling client.
Most other UNIX calls depend only upon the standard set listed above. Thus, all other UNIX calls can be implemented completely on the Cheops side. These functions are prototyped in $G960INC and are linked in by the -L$G960LIB -lcgca library.
This section reviews various commands available to affect chex server / local client communications.
If chex is invoked with the -ser option, the service port is not created and chex terminates immediately after the local client begins execution. This disables client/server communications, and system calls made by the local client that are normally serviced by chex will return with a negative value indicating failure.
Even without chex, however, standard I/O functions like fprintf and fscanf will still be supported thru M7's serial I/O driver.
If you should ever need to terminate the chex host server, but wish to let the local client application remain active, this may be done with the function chex_close_connection(). This function redirects all standard I/O functionality to be handled by the serial I/O device rather than chex, and then terminates the chex program. The locally running application will continue running, but any subsequent host file system calls will return a negative value indicating failure since chex is no longer available to service those requests.
The system call exit()will terminate both the host server as well as the local client.
Use (control-c) to terminate the client before normal program termination. Chex handles this signal by telling the Magic Seven operating system to kill the local process, before chex itself is terminated.
WARNING! : Don't (control-a) in your chterm monitor console window while your local client program is being serviced by chex. Control-a is the Magic Seven soft reboot key which will kill all local processes. Chances are, a process will be in the middle of a SCSI transaction with the chex host server when the reboot occurs. The host's SCSI device driver will then either wait indefinitely for Cheops to complete its side of the transaction (and it can't since it's state has been wiped) or it will simply terminate that connection. Either way, this connection can only be reestablished during the host's reboot cycle, so you want to avoid arbitrarily terminating a program from the Cheops side.
Whereever you call exit() in your local program you may want to call _ioflush() in order to insure that all output reaches their destination. If you do not call exit(), the flush is done automatically at the end of your program.
In a Cheops program, printf commands (more specifically putchar
commands) are directed to its console device. The console can be one
of several devices:
To get and set the console use the functions:
proc_get_console(long proc_no,long *dev,long *service_port)
proc_set_console(long proc_no,long dev,long service_port)
NOTE: All I/O requests are handled by that process' selected console device. Remote file system calls made when the console device is not selected to be SERVICE_PORT will return a negative value indicating failure since they can only be handled by chex via its service_port.
Output redirection can also be done directly to one of the above
devices by using the function:
dev_printf( long dev, char *format,... )
When a program has begun execution, it has been mentioned that chex enters an endless service loop. Chex achieves this by periodically interrupting M7 (via a hardware SCSI interrupt) to see if any messages have arrived for it. This interruption will introduce an effect on the run-time speed of local applications.
The delay time in milliseconds between these service queries that chex makes may be set from the local client with the function chex_set_polling_rate(). The default time between queries is 50 milliseconds.
Increasing this delay value will result in increasing the average time it takes for each remote service request to be handled. However, for those sections of an application that are time critical, significant processing speed up can be achieved by decreasing the number of requests that chex can service and increasing the delay between service queries.
If you reach a point in your application where chex is no longer needed to service host file system calls, use the function chex_close_connection() described above.
Chex also provides full support for standard Media Lab datfile library functions. For an introduction to datfiles, refer to garden man pages man dat, man datio and man datsubs. Prototypes for these funtions may be found in $CHEOPS_LOCAL_INC/cheops_dat.h. Stub functions that make datlib requests to chex are not provided in the standard -lcheops library. To use these functions, the library -lcheops_dat needs to be included in the library list before the -lcheops entry.
These are the standard datlib functions. They should be identical to the function prototypes for host platforms found at /usr/local/include/dat.h.
DATFILE *dxopen (const char *name, const char *mode); DATFILE *d_open (const char *name, const char *mode); long d_flush (DATFILE *df); long d_close (DATFILE *df); long d_gettype (const DATFILE *df, long *nbps); int d_settype (DATFILE *df, int type); char *d_getname(const DATFILE *df); long d_getdim (const DATFILE *df,long *recs,long *chan,long dim[],long maxdim); long d_setdim (DATFILE *df,long dset,long chan,long dim[10],long ndim); long d_copyhdr (DATFILE *to, const DATFILE *from); long d_read(DATFILE *df, char *buf, long n); long d_readc(DATFILE *df, char *buf, long n, long buftype); long d_write(DATFILE *df, char *buf, long n); long d_writec(DATFILE *df, char *buf, long n, long buftype); long d_seek(DATFILE *df, struct d_addr *where, long whence); long d_getsubdim(DATFILE *df,struct d_addr *size); const char *d_getkey (const DATFILE *df, const char *key); int d_setkey (DATFILE *df, const char *key, const char *val); int d_appkey (DATFILE *df, const char *key, const char *val); int d_delkey (DATFILE *df, const char *key); long d_submatrix(DATFILE *df, struct d_addr *start, struct d_addr *stop, struct d_addr *step); long d_getsubmatrix(DATFILE *df, struct d_addr *start, struct d_addr *stop, struct d_addr *step);
Since Cheops differs from general purpose platforms in terms of
multiprocessing capabilities and memory management we have extended
the datfile library to take maximum advantage of these peculiarities.
The utility of providing multiprocessing capabilities by using
semaphored communications has been discussed above for the future_
versions of the standard read() and write() system calls. The same
idea has been extended for datfiles as well.
long d_future_readc(DATFILE *df, char *buf, long len, long type, long sema)
Just as future_read() differs from the standard system call read()
as explained above, the d_future_readc() differs from d_readc() in
only that it requires an extra semaphore that should be SET (refer to
sema_acquire() and sema_allocate() in Magic7 IPC System and prototyped
in $CHEOPS_LOCAL_INC/cheops.h). When invoked by the local
client, the chex server receives this call, but no response is
required (the return long only signals if an error was encountered),
so the client is allowed to continue execution even though the massive
data transfer is not complete. When the data transfer has completed,
chex signals the client by remotely CLEARing the given semaphore using
sema_release(). The client process should check the semaphore's status
using sema_poll() to determine when the transfer has completed.
The d_future_N() function is an extention of d_future_readc(). It
takes an N-lengthed array of datfiles, wheres & whences (see
d_seek()), bufs, lens, and types (see d_readc()). This allows the
client to make multiple complex transfer requests at one time. As with
d_future_readc() this function must be invoked with a SET
semaphore. The return value indicates success of the request but not
completion of the transfer. Completion of all N seeks and transfers is
indicated by a CLEARed semaphore.
Typical datlib transfer functions, like d_readc() and d_writec()
operate on 1-D streams of data. Cheops stream processors operate on
16-bit samples arranged within 1024 long "strides" of samples. This
two dimensional format allows row order processing of image data
(refer to Cheops Memory and Image Management). Chex supports data
transfers of any datfile type into or out 2-D short samples with the
family of d_2d extentions to the datfile library on Cheops.
NOTE: In order for these functions to work correctly, the
horizontal image dimension (xdim) must be a multiple of 16.
The above functions are written OPTIMALLY: each image is read as a
contiguous scsi transfer into a temporarily allocated buffer, and then
quad word converted from byte to short format. They are, however, not
very general in that they strictly impose the limitation that the
destination buffer be of type short and that the source data be first
converted to bytes.
To sidestep these limitations the more general, but less efficient
function, d_2d_readc() is provided. It allows the local client program
to read data from a datfile into any type of 2-D image with the given
stride in bytes.
The d_2d_future_readc() function does the equivelent of
d_2d_readc() but in nonblocking semaphore mode (see d_future_readc):
NOTE: The d_2d_readc functions are very NON-OPTIMAL as each
scan-line is written seperately over scsi.
Multiprocessed Data Transfers via Semaphores
long d_future_N( long N, DATFILE *dat[],
struct d_addr *where[], long whence[],
char *buf[], long len[], long type[], long sema );
Two Dimensional Image Transfers
long d_2d_read_byte_to_lo_short( DATFILE *df,
short *short_addr, long short_stride,
long data_xdim,long data_ydim );
long d_2d_read_byte_to_hi_short( DATFILE *df,
short *short_addr, long short_stride,
long data_xdim, long data_ydim );
long d_2d_write_lo_short_to_byte( DATFILE *df,
short *short_addr, long short_stride,
long data_xdim, long data_ydim );
long d_2d_write_hi_short_to_byte( DATFILE *df,
short *short_addr, long short_stride,
long data_xdim, long data_ydim );
long d_2d_readc( DATFILE *df,
char *byte_addr, long byte_stride,
long data_xdim, long data_ydim, long data_type );
long d_2d_future_readc(DATFILE *df,char *byte_addr,long byte_stride,
long data_xdim,long data_ydim,
long data_type,long sema);
Jump to Software Tools
Jump to the Cheops Homepage