bpo_init - Shared Object and Resource routines

All of the bpo_* routines are based on the idea of shared memory-mapped data. There are two sorts of item that can be memory-mapped, they are System V IPC shared memory and mmap()-ed files.

bpo_init provides the routines which attach and detach these segments and provides a way of registering resources allocated within the segments. The create routines provide the hints which are used with the functions described in the associated files.


The Create Functions

There are two basic functions for attaching to the shared segements, one for each memory type.
    void *Create_SODB_mmap_priv( const char *use_name,
				const char *mmap_name,
				size_t msize,
				off_t moff,
				int flags,
				mode_t priv  );
    void *Create_SODB_shm_priv( const char *use_name,
				const char *fname,
				char id,
				size_t msize,
				int flags,
				mode_t priv );
These functions create/attach the segments used by the other bpo_* routines. They both return a pointer which is normally the base of the mapped object (see note below about SODB_ADD_HEADER).

The functions take both take a use_name parameter which is the name by which this segment will be known. They also take a set of flags which are used to determine the properties of this segment (whether it supports dynamic allocation, etc), and a privileges parameter which determines the permissions on the segment. The other parameters are directly related to the system calls these functions overlay.

In the case of the _mmap function, the parameters are the file name to map, what offset into the file should be used, and how much of the file to map.

For the _shm function the parameters are the file name (which should exist) and the id to use in a call to the ftok() routine, and what the size of the shared memory segment should be.

There are two values that may be passed as the flag. These values are.

SODB_USE_SHALLOC
This specifies that the segment allows dynamic allocation of memory within it using the routines provided in bpo_alloc. Use of the flag enables the use of the resource functions described below.
SODB_ADD_HEADER
This specifies that the size of the shared object header should be added to the requested size, and that the routine, on success, should return a pointer to beyond the shared object header.
If there is a problem at any point during the create/attach the routines return NULL. If the segment required already exists, then the shared object header is checked against the supplied parameters. If any of the parameters does not match (use_name, size, etc.) then the create routine will fail and return NULL.

    void *Create_SODB_mmap( const char *use_name,
			    const char *mmap_name,
			    size_t msize,
			    off_t moff,
			    int flags );
		
    void *Create_SODB_shm( const char *use_name,
			    const char *fname,
			    char id,
			    size_t msize,
			    int flags );
These two routines are simply wrappers for the ones mentioned above, but without the attache privileges parameter. These routines provide default value for this parameter. The new defaults for both of the privileges is 0600, which gives maximum security.

The Detach Functions

These functions detach the segments pointed to by the provided hint. Care should be taken to call the right call corresponding to the Create call used.
    int Detach_SODB_mmap( void *hint );

    int Detach_SODB_shm( void *hint );
There is also a call to use in case you do not know how a particular SODB was attached.
    int Detach_SODB_lump( const void *hint );
This will either detach (shmdt) the shared memory, or munmap the relevant SODB.


Utility Functions

    void *Get_SODB_Pointer( const void *hint, off_t item_offset );
This function returns the pointer within the SODB of the hint for the offset provided (or NULL if not supplied a valid hint for an SODB or the offset if outside the supplied SODB).
    off_t Get_SODB_Offset( const void *vp );
This function returns the offset into the SODB of the supplied object (or 0 if not supplied a valid pointer for an SODB).
    mode_t Get_SODB_Privs( const void *vp );
This function returns the attach mode of the SODB pointed to by the parameter (or 0 if not supplied a valid pointer for an SODB).
    void * Get_SODB_Base( const void *hint );
This function returns a pointer to the start of the SODB which contains the hint (or NULL if the hint is not in an SODB).
    int SODB_in_Segment( const void *hint, const void *chk );
This function returns a non-zero result if the check parameter is within the same SODB as the hint.


The Resource Functions

These functions allow the tracking of allocated sections within a segment by name. These sections are refered to by name, and are stored as a name/offset pair on the resource list (internal).

These functions only work if the initial Create routine was called with SODB_USE_SHALLOC as part of the flags.

    void * Find_SODB_Resource( void *hint, char *res_name );
The function returns a pointer to the named resource, it it exists. If it does not, it returns a NULL. If a given resource is not found it is likely that the following routine will be called.
    off_t Add_SODB_Resource( void *object, char *res_name );
This adds a resource, with the supplied name, to the resource list in the relevant segment. If the resource already exists, or there is a problem in adding the resource (the segment does not support resources) then the routine returns (off_t)0, otherwise it returns the offset within the segment of the supplied object.

    void * Fetch_SODB_Resource( void *hint, char *name, size_t s_size,
                                void (* s_init)( void * ) );
This function provides a wrapper for the Find_ and Add_ resource functions. It is most easily described using the following pseudo-code.
    void * Fetch_SODB_Resource( void *hint, char *name, size_t s_size,
                                void (* s_init)( void * ) )
    {
	void *rv,tp;

	rv = Find_SODB_Resource( hint, name );
	if (rv==NULL)
	{
	    tp = shalloc( hint, s_size );
	    if (tp)
	    {
		(* s_init)( tp );
		if (Add_SODB_Resource( tp, name )==(off_t)0)
		    shfree(tp);
		rv = Find_SODB_Resource( hint, name );
	    }
	}
	return(rv);
    }
As can be seen, we either find it, or create it. Note, we allow for somebody creating it between our search and add. In addition, there are a couple of other safety measures that are taken to ensure that the memory cannot be freed by some rouge program.

The initialise function should perform any base initialisation required to the data area, but should not assume that the pointer passed is going to be the resource (given we may have been pre-empted).

For further clarification, consider the following code.

    struct fred
    {
    struct bpo_pid_lock fred_lock;
    int fred_value;
    };

    static void init_fred( struct fred *fp )
    {
	bpo_Init_pid_lock( &fp->fred_lock, NULL );
	fp->fred_value=1;
	return;
    }

    struct fred * find_fred( void *hint )
    {
	struct fred *fp;
	fp = Fetch_SODB_Resource( hint, "FRED",
				sizeof(struct fred),
				(void (*)(void *))init_fred );
	return(fp);
    }