USINIT(3P) USINIT(3P) NAME usinit, usdetach, usadd, _utrace, _uerror - shared arena initialization C SYNOPSIS #include <ulocks.h> usptr_t *usinit (const char *filename); int usadd (usptr_t *u); void usdetach (usptr_t *u); extern int _uerror; extern int _utrace; DESCRIPTION usinit is used to initialize a shared arena from which related or unrelated processes may allocate and share semaphores, locks and memory. Locks, semaphores and memory can then be allocated using the usptr_t returned by usinit. More than one call can be made to usinit to create separate arenas of locks and semaphores. In fact, calls to usinit may be made on behalf of a process: when sproc(2) is called, an arena containing the locks and semaphores for libc is created; when m_fork(3P) is called, an arena is set up to control the spawned tasks. usinit uses a file in the file system to name the arena. This name can then be used by unrelated processes to access the arena. usinit creates a file, filename, and maps it into the caller's space via mmap(2). The file is mapped using the MAP_AUTOGROW option to mmap(2) (see usconfig(3P) for ways to alter this behavior). By default the file is not removed when the last process using it is finished. This behavior can be modified somewhat via usconfig(3P). File locks (see fcntl(2)) are used to prevent conflicting accesses to this area during the usinit call. There is no way to tell the id of the process that actually created the arena. The file name given to usinit may be an NFS mounted file, however it is important to understand that NFS does not guarantee write synchronization across multiple machines - thus if all users of an arena are running on a single machine and using an NFS mounted file as the arena, then all will work fine. If multiple users running on different machines all access the same arena file, the arena will be corrupted. Gaining access to a particular arena for the purpose of sharing locks, semaphores, and memory is dependent on how the processes are related and how the arena was initialized. If the arena was initialized (which is the default) without the US_SHAREDONLY option to usconfig(3P) then any process with the appropriate permissions can join the arena at any time by calling usinit with filename. These processes may be unrelated, related via fork, related via sproc sharing file descriptors, or related via sproc not sharing file descriptors. If the arena was initialized with the US_SHAREDONLY option to usconfig(3P) then the file specified by filename is unlinked. This means that the only processes that can join the arena must somehow already have a handle for that arena (i.e. the arena must already be mapped into their address space). Unrelated processes, processes spawned via fork before the arena was initialized, and process spawned via sproc and not sharing file descriptors, can never get the appropriate handle. If a process with the above characteristics calls usinit with filename a NEW arena will be created that has no relation to any other process's arena. Processes that have the correct handle are automatically made 'members' of the arena the first time they use a lock or semaphore. They may choose to call usadd explicitly so that any potential errors are detected at initialization time, rather than the first time a lock or semaphore is used. Previous versions of this manual page suggested calling usinit rather than usadd. This still works for any arena except one using /dev/zero. usadd will work for any arena. Certain attributes of the newly created arena may be set prior to the call to usinit by usconfig(3P). These include the maximum number of users that can simultaneously access the arena, the maximum size the arena can grow to, the access permissions on the arena, the type of debugging enabled, and where in the caller's address space the arena will be attached. The overall size will limit how many locks and semaphores may be allocated and how much space in the arena is left over for the user to allocate via usmalloc(3P). In addition to the arena header, basic lock, and semaphore data structures, all history, metering and debug structures are also allocated via usmalloc(3P) from the arena. The default size is 64K, and the default number of users is 8. When called, usinit attempts to determine whether the arena described by filename is active (i.e. whether any other processes are currently using it). This determination is made by checking whether any file locks are currently active on the file. If so, the caller registers its file lock and merely 'joins' the collection of processes using that arena. If there are no file locks, the caller re-initializes the entire arena. Problems can result if a process that did not call usinit is still accessing the arena (namely a child of a sproc whose parent has died) when a new process attempts to join. The new process will find no file locks and re-initialize the arena, thus destroying any state the first process had. This problem can be solved by having all processes register with the arena by calling usadd. Previous versions of this manual page suggested calling usinit rather than usadd. This still works for any arena except one using /dev/zero. usadd will work for any arena. As a special case, /dev/zero can be passed as the value for filename. Since /dev/zero by definition is private to the process that opens it, this is useful only for share group members that are sharing file descriptors. The space for /dev/zero comes from the logical swap pool (see swap(1M)) rather than from the file system. Depending on the system configuration there may be more space in the logical swap pool than on a file system. The logical swap pool is also a limited resource and usinit may fail due to lack of logical swap. It is possible to delay allocation of logical swap (much like the MAP_AUTOGROW option delays growth of files) by using the CONF_AUTORESV option of usconfig(3P). usinit and the other lock and semaphore routines normally perform their functions in silence. For a verbose 'trace' of what is being done, the global flag _utrace may be set to non-zero. In addition, if the environment variable USTRACE is set, usinit will automatically set _utrace. The tracing information consists of two types of messages - trace and error. Error type messages can be enabled independently from tracing messages by setting the global flag _uerror. In addition, if the environment variable USERROR is set, usinit will automatically set _uerror. All messages are printed on stderr. This may aid in debugging the various error returns. An arena, once established, must reside at the same virtual address in each process that attaches to it. This implies that if more than one process is creating an arena, the creating processes must impose the appropriate ordering. The following scenario will lead to such an ordering problem: process A creates arena A_arena, and process B creates arena B_arena. Then process A attempts to attach (via usinit) to B_arena. usinit will most probably fail in this case since the virtual address for both arenas will probably be identical. One way around this ordering problem is to use usconfig(3P) to manually set the address where the arena should be attached. It is then only important that all arena creating processes agree on the addresses for each of the arenas. Another easy way around this problem is to have all arenas created by one process. A process may detach an arena by calling usdetach. This call will unmap and close all the relevant file descriptors. It does not check for any outstanding locks, allocated memory, etc. usdetach will not close any pollable semaphores, this must be done before calling usdetach. For sproc processes sharing file descriptors, if one member calls usdetach then the arena is detached for the entire share group. There is no protection for multiple members of a share group simultaneously calling usdetach, this should not be done. If usinit fails, it is a good idea to set the tracing variable _utrace to 1 or set the environment variable USTRACE). This will provide more descriptive error messages. usinit or usadd will fail if one or more of the following are true: EACCES The filename argument could not be opened or created for read/write. ENOSPC The file specified by filename could not be grown to the specified size. ENOMEM There is not enough space in the arena to allocate the initial set of required locks and semaphores. The size of the arena may be manipulated with usconfig(3P). EBUSY The caller already has mapped virtual space at the address requested with the CONF_ATTACHADDR option of usconfig. EBUSY The caller already has mapped virtual space at the address required by the arena when attempting to join the arena. ENXIO One or both of the two semaphore device files, /dev/usema and /dev/usemaclone, do not exist, or the device is not configured into the system. EINVAL This error is returned if the version the currently attaching process was compiled with is incompatible with the version compiled into the creator of the arena. ENOLCK There are no more file locks available because the system maximum {FLOCK_MAX} [see intro(2)], has been exceeded. ENOLCK filename is in an NFS-mounted directory, and either the NFS lock daemon, lockd(1M) is not running (either on the server or client) or the maximum number of file locks that lockd can handle has been exceeded. EAGAIN filename was set to /dev/zero and there isn't enough logical swap space to map the requested size arena. Errors may also be the result of a mmap(2) or a fcntl(2) system call. SEE ALSO fcntl(2), mmap(2), sproc(2), acquire_lock(3), barrier(3P), oserror(3C), uscasinfo(3P), usconfig(3P), usgetinfo(3P), usmalloc(3P), usnewlock(3P), usnewsema(3P). DIAGNOSTICS Upon successful completion, usinit returns a pointer to a usptr_t structure. Otherwise, a value of NULL is returned and errno is set to indicate the error. Upon successful completion, usadd returns zero. Otherwise a value of negative one is returned and errno is set to indicate the error. BUGS usinit string compares filename with the names of existing arenas in the calling process. If it finds a match, it assumes that the arena already exists and that the caller has already (due to already having called usinit with the same filename or due to being related to the process that created the arena) mapped in the arena. This can cause unexpected results if the application has code along the following lines: filename = strdup(template); mktemp(filename); arena = usinit(filename); (fork, exec, communicate file name to other process, it attaches to arena) unlink(filename); The second time this is done, mktemp could come up with the exact same name file as before (since the first one was unlinked). When usinit compares the name to the names of already existing and mapped arenas, it will find a match and NOT create a new arena. Certainly, in this case, not the desired result. WARNINGS Currently, it is not possible to create a shared arena that can be used by programs of differing ABIs. This means that o32, N32, and N64 programs cannot share an arena. For primitives that can be shared between 32-bit and 64-bit processes see abilock(3P) and test_and_set(3P). Page 5