|
|
|
nob_util
- Named Object Utilities
The Named Object (NOB) utilities provide a general means of assigning names to arbitrary objects so that other tasks can access the objects by name.
The NOB utilities are intended for, but not limited to, use in library functions that both create new objects and access existing objects. An application can call such a library function without caring if the target object exists or not - the object will be created automatically if need be. For example, message queues are known by their ID under UNIX. A library function that creates new named message queues or accesses existing ones would use the NOB utilities as follows:
#include <errno.h> -- System error definitions. #include <sys/ipc.h> -- Inter-process communication definitions. #include <sys/msg.h> -- Message queue definitions. #include "nob_util.h" -- Named object definitions. int queue ; NamedObject qobj ; ... if (!nobCreate ("MY_MSGQ", singleCPU, &qobj)) { queue = msgget (IPC_PRIVATE, -- Brand new? (IPC_CREAT | 0620)) ; nobCommit (qobj, (void *) queue) ; } else if (errno == EEXIST) { -- Already exists? queue = (int) nobValue (qobj) ; } else { -- Error? ... error ... }
If the named queue already exists, the queue ID is retrieved from the
object by calling nobValue()
. If the queue doesn't exist,
the queue is created and its ID is then stored in the object by a call to
nobCommit()
. The creation of a new object can be aborted in
the event of an error by calling nobAbort()
instead of
nobCommit()
.
Processes that know an object exists or that depend upon the object
existing can call nobExists()
to lookup an object's value:
qobj = nobExists ("MY_MSGQ", singleCPU) ; if (qobj == NULL) { -- Doesn't exist or error? ... error ... } else { -- Exists? queue = (int) nobValue (qobj) ; }
Deleting the named message queue is done as follows:
if (!nobDestroy (qobj)) { -- Last user of queue? msgctl (queue, IPC_RMID, NULL) ; } else if (errno != EWOULDBLOCK) { -- Error? ... error ... }
Note that the last task using the message queue is the one that actually deletes the queue.
Under UNIX, the named object database is implemented using the
ndbm(3)
database facility. The base ndbm(3)
pathname for the named object database files defaults to
/tmp/nob_database
; the user can specify a different pathname in
environment variable, NOB_DATABASE
.
If the directory in which the database files are stored is NFS mounted on
multiple machines, the database is visible on each of those machines. The
multi-system lockf(3)
facility - lockf(2)
depending on your OS - is used to prevent simultaneous updates to the
database.
Since objects such as message queues and semaphores are only accessible from the CPU on which they are created, be wary of storing their "values" (IPC IDs) in an NFS-mounted, multi-CPU NOB database.
ndbm(3)
caches retrieved records and updates in memory on a
per-process basis. To make sure every process sees the same database, the
cached images must be synchronized with the disk image before each database
fetch and after each database store. The synchronization is performed by
closing and reopening the database - a brute force approach, but no other
solution has presented itself.
To prevent alignment errors (which occurred in my first version), the
unaligned records returned by dbm_fetch()
are copied into
local, aligned record storage.
Under VxWorks, the "named object database" is implemented using the system
symbol table and, when VxMP is available, the shared memory database. The
single-/multi-CPU scope argument to nobCreate()
provides for a
two-level database.
A semaphore is used to prevent simultaneous updates to the "named object
database". This semaphore is itself accessed by name by different tasks.
For local symbols (or on a non-VxMP system), the semaphore's name is stored
in the system symbol table, which allows multiple instances of a symbol.
It is possible that N
tasks could simultaneously find the
semaphore absent from the symbol table, create N
new
semaphores, and add N
semaphores to the symbol table. To
prevent this from happening, the tasks are allowed to create the semaphore,
but then an internal function, nobExamine()
, scans the symbol
table for the earliest-added NOB semaphore; that semaphore becomes
the NOB semaphore; all others are deleted by the tasks who created
them. (Scanning the symbol table might seem slow, but it only happens when
the semaphore is not found in the table; once the semaphore is created, no
scanning is necessary.)
A separate semaphore is used for global symbols on a VxMP system. This semaphore's name is entered in the VxMP shared memory database, which doesn't allow multiple instances of a given symbol. Under VxMP, the objects are stored in VxMP shared memory; the NOB functions make the appropriate global-to-local address conversions. However, if an object's value requires conversions, the creator and users of the object are responsible for performing the necessary conversions.
Tasks that terminate prematurely or that don't delete their objects can leave the "named object database" in an indeterminate or unaccessible state.
nobAbort()
- aborts the creation of a named object.nobCommit()
- finalizes the creation of a named object.nobCount()
- returns the number of tasks referencing a
named object.nobCreate()
- creates a named object.nobDestroy()
- deletes a named object.nobExists()
- looks up a named object.nobName()
- returns a named object's name.nobReference()
- registers a reference to a named object
through an existing handle.nobValue()
- returns a named object's value.nob_util.c
(UNIX)nob_vx.c
(VxWorks)nob_util.h