getloadavg()
Record Locking is the term normally used to describe the ability
of a process to prevent other processes from modifying a region of a file,
while the first process is reading or modifying that portion of the file.
POSIX.1 bases it's record locking mechanism on the fcntl
function:
#include <sys/types.h> #include <unistd.h> #include <fcntl.h> /* * Returns: * -1 on error */ int fcntl(int filedes, int cmd, ... /* struct flock *flockptr */ );
We'll start with the third argument (flockptr), which points to a flock
structure:
struct flock { short l_type; /* F_RDLCK (shared read lock), or * F_WRLCK (shared write lock), or * F_UNLCK (unlocking a region) */ off_t l_start; /* offset in bytes, relative to l_whence */ short l_whence; /* SEEK_SET: file's offset is set to * l_start bytes from beginning of file * SEEK_CUR: file's offset is set to its current value * plus the l_start (which can be + or -) * SEEK_END: file's offset is set to the size of the file * plus the l_start (which can be + or -) */ off_t l_len; /* length of region, in bytes * special case: if (l_len == 0), it means that the lock * extends to the largest possible offset of the file. * This allows us to lock a region starting anywhere in * the file, up through and including any data that is * appended to the file */ pid_t l_pid; /* returned when cmd = F_GETLK */ }
This structure describes:
l_start
and l_whence
), and
l_len
)
To lock an entire file, set l_start
and l_whence
to
point to the beginning of the file (i.e. l_start
= 0, l_whence
=
SEEK_SET), and specify a length (l_len
) of 0.
Any number of processes can have a shared read lock on a given byte, but only one process can have an exclusive write lock on a given byte. To obtain a read lock the descriptor must be open for reading, and the region cannot have an exclusive write lock. To obtain a write lock the descriptor must be open for writing, and the region cannot have an exclusive write lock nor any read locks.
Now, we will describe the second parameter (cmd) for fcntl
.
The possible commands are:
F_GETLK | Determine if the lock described by flockptr is blocked
by some other lock. If a lock exists that would prevent ours from being created, the information
on that existing lock overwrites the information pointed to by flockptr. If no lock
exists that would prevent ours from being created, the structure pointed to by flockptr
is left unchanged except for the l_type member, which is set to F_UNLCK. |
F_SETLK | Set the lock described by flockptr. If we are unable
to obtain a lock (because of previous locks already granted for the region) then
fcntl returns -1 and errno is set to either
EACCES or EAGAIN |
F_SETLKW | This command is a blocking version of F_SETLK (the W in the command means "wait"). If the requested read lock or write lock cannot be granted because another process currently has some part of the requested region locked, the calling process is put to sleep. This sleep is interrupted is a signal is caught. |
Be aware that testing for a lock with F_GETLK and then trying to obtain that lock
with F_SETLK or F_SETLKW is not an atomic operation. We have no guarantee that between
the two fcntrl
calls some other process won't come in and obtain
the same lock.
To save ourselves the trouble of allocating a flock
structure and filling
in all the elements each time, Stevens defines the function lock_reg
and a number of macros that call it. Notice that the macros shorten the number
of parameters by two, and save us the grief of remembering the F_* constants mentioned
above.
#define read_lock(fd, offset, whence, len) \ lock_reg (fd, F_SETLK, F_RDLCK, offset, whence, len) #define readw_lock(fd, offset, whence, len) \ lock_reg (fd, F_SETLKW, F_RDLCK, offset, whence, len) #define write_lock(fd, offset, whence, len) \ lock_reg (fd, F_SETLK, F_WRLCK, offset, whence, len) #define writew_lock(fd, offset, whence, len) \ lock_reg (fd, F_SETLKW, F_WRLCK, offset, whence, len) #define un_lock(fd, offset, whence, len) \ lock_reg (fd, F_SETLK, F_UNLCK, offset, whence, len) int lock_reg(int fd, int cmd, int type, off_t offset, int whence, off_t len) { struct flock lock; lock.l_type = type; /* F_RDLCK, F_WRLCK, F_UNLCK */ lock.l_start = offset; /* byte offset, relative to l_whence */ lock.l_whence = whence; /* SEEK_SET, SEEK_CUR, SEEK_END */ lock.l_len = len; /* #bytes (0 means to EOF) */ return ( fcntl(fd, cmd, &lock) ); }
There are 3 important rules regarding automatic inheritance and release of record locks:
fork
(otherwise
we could end up with two processes sharing a write lock)
exec
. This
is not required by POSIX.1 and therefore machine dependent
getloadavg()
Purpose:
getloadavg
returns the system load averages.
Declaration:
#include <sys/loadavg.h> /* returns: * on success, the # of samples actually retrieved * on error, -1 */ int getloadavg(double loadavg[], int nelem);
Parameters:
loadavg
: this gets filled with load averages. It should be of >=
the value of nelem
.
You can access particular load averages using the following constants
as indexes: LOADAVG_1MIN ( = 0), LOADAVG_5MIN ( = 1), and LOADAVG_15MIN ( = 2).
nelem
: the number of samples to retrieve. A sensible value is
between 1 and 3.