next up previous
Next: 3.5 Signals Up: 3.4 Files Previous: 3.4 Files


3.4.1 Augmenting System Calls

As described above, we need to record information from system calls such as open() without any modification of the user code. We do this by providing our own version of open() which records the information then calls the system provided open() routine. A straightforward implementation of this would result in a naming conflict, i.e. our open() routine would cover up the system open() routine.

The UNIX man pages make a distinction between ``system calls'' and ``C library routines'' (system calls are described in section 2, and library routines are described in section 3). However, from the programmer's point of view, these two items appear to be very similar. There may seem to be no fundamental difference between a call to write() and a call to printf() - each is simply a procedure call requesting some service provided by ``the system''. To see the difference, consider the plight of a programmer who wants to alter the functionality of each of these calls, but doesn't want to change their names. Keeping the names the same will be crucial if one wants to link the altered write() and printf() routines with existing code which should not be aware of the change. The programmer wanting to change printf() has at his or her disposal all the tools and routines available to the original designer of printf, but the programmer wanting to change write() has a problem. How can one get the kernel to transfer data to the disk without calling write()? We cannot call write() from within a routine called write() - that would be recursion, and definitely not what is wanted here. The solution is a little known routine called syscall(). Every UNIX system call is associated with a number (defined by a macro in <syscall.h>). One can replace an invocation of a system call with a call to the syscall routine. In this case the first argument is the system call number, and the remaining arguments are just the normal arguments to the system call. The following write() routine simply counts the number of times write() was called in the program, but otherwise acts exactly like the normal write().

int	number_of_writes = 0;
write( int fd, void *buf, size_t len )
	return syscall( SYS_write, fd, buf, len );

Interestingly, this trick works even if the user code never calls write() directly, but only indirectly - for example via printf(). The condor checkpointing code uses this mechanism to augment the functionality of a number of system calls. For example, we augment the open() system call so that it records the name of the file being opened, and the file descriptor number returned. This information is later used to re-open the file at restart time.

next up previous
Next: 3.5 Signals Up: 3.4 Files Previous: 3.4 Files