spl_request(3C)
NAME
spl_map, spl_request, spl_unmap, spl_request_macro − system interrupt priority level controls
SYNOPSIS
#include <sys/types.h>
#include <ml/spl.h>
caddr_t spl_map (addr)
caddr_t addr;
int spl_unmap (addr)
caddr_t addr;
void spl_request (value, addr)
u_int value;
caddr_t addr;
spl_request_macro (value, addr, pv)
u_int val;
caddr_t addr;
u_int pv;
DESCRIPTION
The system interrupt priority level, ipl, may be modified from user-level, by using this set of spl library routines. This is accomplished by binding the physical address of the system interrupt priority register into the address space of the process, and then writing directly to this hardware register from the process’s address space.
By raising a cpu’s ipl from the normal user-level value of zero, a process may hold out certain interrupts. For example, by raising the ipl to SPL4, a process holds out all VME level 4 interrupts, which would prevent level 4 VME devices from interrupting the process’s cpu.
The spl_map() routine binds the physical address of the ipl register into the address space of the process and returns the resulting virtual address of the interrupt priority register. This is accomplished by creating a shared memory region. The addr parameter is a virtual address where the caller wishes the shared memory region to be attached. If addr is zero, the system will pick the virtual address. If addr is not zero, then spl_map() will attempt to attach the shared memory region at the specified address, automatically rounding the addr value to a SHMLBA boundary.
Certain library routines, such as those contained in a user-level device driver, may make spl_map() calls in addition to spl_map() calls made by the non-library code portion of the program. Therefore, if a process makes more than one call to spl_map() before making a spl_umap() call, an attempt will be made to use the previously bound spl shared memory region. In this case, spl_map() will simply increment an internal reference count and return the previously bound virtual address. However, if an addr parameter is specified on an additional spl_map() call and the address does not match the previously bound spl region’s address, an error wil be returned.
The spl_request() routine sets the ipl to the specified interrupt priority level. The value parameter should be an ipl value that is defined in the <ml/spl.h> include file. The addr parameter should be the virtual address value that was returned from a previous spl_map() call. spl_request() returns the previous ipl value; that is, the value of the ipl register before it was modified to the caller’s specified value.
The spl_request_macro() macro is provided as a faster method for modifying the ipl register. The value and addr parameters should contain the same information as the spl_request() routine. The pv parameter should be an u_int variable where the previous ipl value will be returned. (The pv parameter should always be supplied.) This macro is only available to C language programs and is not available to Fortran or Ada programs.
The spl_unmap() routine is provided to detach the shared memory region from the process. The addr parameter is the virtual address returned from the previous spl_map() routine call. (The spl shared memory region will be automatically detached when a process terminates, or issues one of the exec(2) system service calls.)
If the process has made multiple calls to spl_map() before calling spl_unmap(), the spl region will not actually be detached until the corresonding number of spl_unmap() calls have been made.
NOTES
These routines would normally be used to coordinate shared data accesses between user-level processes and user-level interrupt routine(s). (See iconnect(2) for more information on user-level interrupt routines). By raising the ipl up to or higher than the interrupt priority level of the user-level interrupt routine’s external interrupt, the user-level proces may then be assured that it may execute on it’s cpu without being interrupted by its corresponding user-level interrupt routine process.
On multiprocessor systems, an additional user-level spin lock should be used, to provide synchronization to shared data among multiple cpus. The spin_init(2), spin_trylock(2), spin_islock(2), spin_unlock(2) set of services are recommended for this purpose. See this man page for more information on using these services.
For example, on a multiprocessor system, a user-level process that shares data with a user-level interrupt process that needs to synchronize its access to this data would do so by:
Raising ipl to the appropriate level.
Locking the user defined spin lock.
Accessing or modifying the shared data.
Unlocking the user defined spin lock.
Lowering ipl to zero.
The corresponding user-level interrupt routine process would access this same data by:
Locking the user defined spin lock
Accessing or modifying the shared data.
Unlocking the user defined spin lock.
RESTRICTIONS
A process must be super-user, or must have the ACC_SHMBIND access vector bit set in order to use the spl_map() routine.
During the time that a process has raised ipl until it has lowered ipl back to zero, the process should not:
Make any system service calls.
Reference any memory location that will result in a system page fault. It is highly recommended that the process lock down its entire address space if it intends to use the spl_request() routine.
Set any debugger breakpoints, or single-step in any section of code where ipl has been set above zero.
It is recommended that a process not raise ipl above zero for any length of time.
WARNINGS
A user-level process (not a user-level interrupt routine process) that raises ipl should ALWAYS reset the ipl back to zero.
If a user-level interrupt routine temporarily raises ipl, it should not set the ipl back to zero, but it should restore the ipl value back to what it was when it entered the user-level interrupt routine. This should be the value that was returned on the initial spl_request() call. See iconnect(2) for more information on user-level interrupt routines.
RETURN VALUE
For spl_map() routine calls, upon successful completion, the virtual address of the ipl register is returned. For spl_unmap() routine calls, upon successful completion, a value of zero is returned. Otherwise, for both of these calls, a value of -1 is returned and errno is set to indicate the error.
The spl_request() routine returns no error status.
ERRORS
If any of the following conditions is detected, spl_map() will return -1 and set errno to the following value:
[EACCES] The caller is not super-user, or does not have the ACC_SHMBIND access vector bit set (if access vectors are configured).
[EINVAL] The addr parameter is not a valid shared memory segment value.
[EBUSY] The process has previously called spl_map(), and the current addr parameter that was specified does not match the previous bind address. The proces must first call spl_unmap() before binding the spl shared memory region to a new virtual address.
[EMFILE] The number of shared memory segments attached to the calling process would exceed the system-imposed limit.
[ENOSPC] The spl shared memory identifier is to be created, but the system-imposed limit on the maximum number of allowed system-wide shared memory identifiers would be exceeded.
If the following condition is detected, spl_unmap() will return -1 and set errno to the following value:
[EINVAL] The specified addr parameter was not a valid segment start address of the ipl shared memory segment.
SEE ALSO
iconnect(2), eti_map(3C), spin_init(2)
CX/UX Programmer’s Reference Manual