Writing Device Drivers

Event Name-Value Pairs

For interfaces such as ddi_log_sysevent(9F), the Solaris DDI provides a way to store information in name-value pairs. Name-value pairs are retained in an nvlist_t structure, which is opaque to the driver.

The value for a name-value pair may be a boolean, an int (16, 32, and 64-bit, signed or unsigned), a string, or an array of ints, bytes, or strings.

The steps in creating a list of name-value pairs are as follows.

  1. Create an nvlist_t structure with nvlist_alloc(9F).

    The nvlist_alloc(9F) interface takes three arguments. The first is a pointer to an nvlist_t structure.

    The second is a flag relating to the uniqueness of the names of the pairs. If this flag is set to NV_UNIQUE_NAME_TYPE, any existing pair in the list will be removed if a new pair with the same name and type is added. If the flag is set to NV_UNIQUE_NAME, then any existing pair with the same name as one being added will be removed, regardless of its type. Specifying NV_UNIQUE_NAME_TYPE allows a list to contain two or more pairs with the same name, as long as their types are different, whereas with NV_UNIQUE_NAME only one instance of a pair name can be in the list. If neither value is used, then no uniqueness checking is done, and the consumer of the list must parse it in such a way as to ensure that any pair retrieved is the one wanted.

    The third argument relates to kernel memory allocation policy. If it is set to KM_SLEEP, then the driver will block until the requested memory is available for allocation. KM_SLEEP allocations may sleep but are guaranteed to succeed. KM_NOSLEEP allocations are guaranteed not to sleep but may fail (return NULL ) if no memory is currently available.

  2. Populate the nvlist with name-value pairs. For example, to add a string, use nvlist_add_string(9F); to add an array of 32-bit integers, use nvlist_add_int32_array(9F). The nvlist_add_boolean(9F) man page contains a complete list of interfaces for adding pairs.

To deallocate a list, use nvlist_free(9F).


Example 4–2 Creating and Populating a Name-Value Pair List

nvlist_t*
create_nvlist()
        {
        int err;
        char *str = "child";
        int32_t ints[] = {0, 1, 2};
        nvlist_t *nvl;
        err = nvlist_alloc(&nvl, 0);    /* allocate list */
        if (err)
                return (NULL);
        /* name="child" & prop={0, 1, 1} */
        if ((nvlist_add_string(nvl, "name", str) != 0) ||
            (nvlist_add_int32_array(nvl, "prop", ints, 3) != 0)) {
                    nvlist_free(nvl);
                    return (NULL);
        }
        return (nvl);
}

Drivers can retrieve the elements of an nvlist by using a lookup function for that type, such as nvlist_lookup_int32_array(9F), which takes as its arguments the name and type of the pair being searched for. Note, however, that these interfaces will only work if either NV_UNIQUE_NAME or NV_UNIQUE_NAME_TYPE was specified when nvlist_alloc(9F) was called.

Name-value lists can be placed in contiguous memory (for example, to pass them to another process or send them to another host). To do so, first get the size of the memory block needed for the list with nvlist_size(9F), and then pack the list into the buffer with nvlist_pack(9F). The consumer receiving the buffer's content can unpack the buffer with nvlist_unpack(9F).