Categories
Uncategorized

The Linux kernel container_of macro

The Linux kernel contains a very useful macro named “container_of” that is used extensively in back-casting a data structure to its containing data structure.  This article includes a simple program that illustrates how this macro is used, and explains why it is so useful.

If you do a lot of C programming, this program is worth figuring out :-).

The program source can also be downloaded from the following location: http://bec-systems.com/linux/linux_container_of_example.c

/* test code to illustrate use of Linux kernel container_of macro
 *
 * Copyright (c) 2008 Cliff Brake, BEC Systems LLC
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

/* This program illustrates how the container_of macro works.
 * The container of macro is very useful in multi layered
 * software systems where you have progressivly more detailed
 * software layers.  Below is an example of a bus layer,
 * and then a device layer where a number of different
 * devices might register with the bus.
 * The device registers itself with the bus subsystem, and
 * then the bus subsystem makes a callback into the device.
 * Normally if there are multiple devices registered, the
 * bus subsystem must store and pass a device structure
 * when making callbacks.  With the container_of macro, this is
 * no longer necessary, and the bus subsystem only has to
 * know about one generic device structure, and does not need visibility
 * into lots of different device structures, or do tricks
 * by casting void pointers, etc.  With the container_of macro
 * we can backcast from the generic data structure, to the containing
 * datastructure.  This forces good separation of code in that
 * that bus layer cannot modifiy data structures that are specific
 * to the device layer.
 *
 */

/**
 * (from Linux kernel source)
 * container_of - cast a member of a structure out to the containing structure
 * @ptr:	the pointer to the member.
 * @type:	the type of the container struct this is embedded in.
 * @member:	the name of the member within the struct.
 *
 */
#define container_of(ptr, type, member) ({			\
	const typeof( ((type *)0)->member ) *__mptr = (ptr);	\
	(type *)( (char *)__mptr - offsetof(type,member) );})

#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)

/*==========================================================
 * BUS layer code
 *==========================================================*/

/* generic bus device structure */
struct bus_device
{
	int general_device_param_a;
	int general_device_param_b;
	void (*device_callback)(struct bus_device * bd);
};

/* the following is a global list of
 * devices that have registered with the
 * bus subsystem.  Normally this would
 * be something like a dynamic linked list.
 */
struct bus_device * bd_list[5];

/* function to register a device with the bus */
void register_with_bus(struct bus_device * bd)
{
	/* since this example only deals with one
	 * device, will put it in slot 0
	 */

	bd_list[0] = bd;
}

void start_bus()
{
	int i;
	struct bus_device * bd;

	/* make callbacks to all devices on bus */
	for (i=0;i<sizeof(bd_list)/sizeof(bd_list[0]);i++) {
		bd = bd_list[i];
		if (!bd) continue;
		/* call device callback with generic
		 * bus device structure
		 */
		bd->device_callback(bd);
	}
}

/*==========================================================
 * device X specific code
 * this would normally be in a different module
 *==========================================================*/

/* structure that holds device X specific stuff, as well as
 * generic bus_device structure
 */
struct device_x
{
	int device_x_specific_param_a;
	int device_x_specific_param_b;
	struct bus_device bd;
};

void device_x_callback(struct bus_device * bd)
{
	/* if we know the structure type that contains the bus_device structure,
	 * we can extract a pointer to the containing structure using the container_of
	 * macro
	 */

	/*                                   ptr       type       member  */
	struct device_x * devx = container_of(bd, struct device_x, bd);

	/* the above statement expands to
	 * struct device_x * devx = (
	 * {
	 *   const typeof( ((struct device_x *)0)->bd ) *__mptr = (bd);
	 *   (struct device_x *)( (char *)__mptr - ((size_t) &((struct device_x *)0)->bd) );
	 * }
	 * );
	 */  

	printf("device_x_callback called!, device_x_specific_param_a = %i\n",
			devx->device_x_specific_param_a);
}

void device_x_init()
{
	/* dynamically allocate structures */
	struct device_x * devx = malloc(sizeof(*devx));
	memset(devx, 0, sizeof(*devx));

	/* set a parameter in the device_x structure so
	 * we can test for this in the callback
	 */
	devx->device_x_specific_param_a = 1001;

	/* set up callback function */
	devx->bd.device_callback = device_x_callback;

	/* we register the generic bus device structure
	 * as the bus layer does not need to know
	 * about the device_x stucture.  Note, the
	 * devx structure is not stored anywhere, yet
	 * its location is being preserved without
	 * specifically passing it to the bus
	 * layer.
	 */
	register_with_bus(&devx->bd);
}

int main()
{

	/* test the above system */

	/* first, initialize device_x */
	device_x_init();

	/* now, start the bus.  This should make
	 * a callback into the device_x
	 */
	start_bus();
}

/* when run, this program returns:
 * device_x_callback called!, device_x_specific_param_a = 1001
 */