Free Trial

Safari Books Online is a digital library providing on-demand subscription access to thousands of learning resources.


  • Create BookmarkCreate Bookmark
  • Create Note or TagCreate Note or Tag
  • DownloadDownload
  • PrintPrint
Share this Page URL
Help

4. Thread Synchronization > Implementing Mutexes

Implementing Mutexes

Example 4-3 is a revision of Example 4-1 that uses a mutex to serialize access to race_list.

Note

To save space, the functions race_ioctl, race_new, race_find, and race_destroy aren’t listed here, as they haven’t been changed.

Example 4-3. race_mtx.c

#include <sys/param.h>
  #include <sys/module.h>
  #include <sys/kernel.h>
  #include <sys/systm.h>

  #include <sys/conf.h>
  #include <sys/uio.h>
  #include <sys/malloc.h>
  #include <sys/ioccom.h>
  #include <sys/queue.h>
  #include <sys/lock.h>
  #include <sys/mutex.h>
  #include "race_ioctl.h"

  MALLOC_DEFINE(M_RACE, "race", "race object");

  struct race_softc {
          LIST_ENTRY(race_softc) list;
          int unit;
  };

  static LIST_HEAD(, race_softc) race_list = LIST_HEAD_INITIALIZER(&race_list);
 static struct mtx race_mtx;

  static struct race_softc *      race_new(void);
  static struct race_softc *      race_find(int unit);
  static void                     race_destroy(struct race_softc *sc);
  static d_ioctl_t                race_ioctl_mtx;
  static d_ioctl_t                race_ioctl;

  static struct cdevsw race_cdevsw = {
          .d_version =    D_VERSION,
        .d_ioctl =      race_ioctl_mtx,
          .d_name =       RACE_NAME
  };

  static struct cdev *race_dev;

  static int
 race_ioctl_mtx(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
      struct thread *td)
  {
          int error;

        mtx_lock(&race_mtx);
          error = race_ioctl(dev, cmd, data, fflag, td);
        mtx_unlock(&race_mtx);

          return (error);
  }

  static int
  race_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
      struct thread *td)
  {
  ...
  }

  static struct race_softc *
  race_new(void)
  {
  ...
  }

  static struct race_softc *
  race_find(int unit)
  {
  ...
  }

  static void
  race_destroy(struct race_softc *sc)
  {
  ...
  }

  static int
  race_modevent(module_t mod __unused, int event, void *arg __unused)
  {
          int error = 0;
          struct race_softc *sc, *sc_temp;

          switch (event) {
          case MOD_LOAD:
                  mtx_init(&race_mtx, "race config lock", NULL, MTX_DEF);
                  race_dev = make_dev(&race_cdevsw, 0, UID_ROOT, GID_WHEEL,
                      0600, RACE_NAME);
                  uprintf("Race driver loaded.\n");
                  break;
          case MOD_UNLOAD:
                  destroy_dev(race_dev);
                  mtx_lock(&race_mtx);
                  if (!LIST_EMPTY(&race_list)) {
                          LIST_FOREACH_SAFE(sc, &race_list, list, sc_temp) {
                                  LIST_REMOVE(sc, list);
                                  free(sc, M_RACE);
                          }
                  }

                  mtx_unlock(&race_mtx);
                  mtx_destroy(&race_mtx);
                  uprintf("Race driver unloaded.\n");
                  break;
          case MOD_QUIESCE:
                  mtx_lock(&race_mtx);
                  if (!LIST_EMPTY(&race_list))
                          error = EBUSY;
                  mtx_unlock(&race_mtx);
                  break;
          default:
                  error = EOPNOTSUPP;
                  break;
          }

          return (error);
  }

  DEV_MODULE(race, race_modevent, NULL);

This driver declares a mutex named race_mtx, which gets initialized as a sleep mutex in the module event handler.

Note

As you’ll see, a mutex is not the ideal solution for Example 4-1. However, for now, I just want to cover how to use mutexes.

In Example 4-1, the main source of concurrent access to race_list is the race_ioctl function. This should be obvious, because race_ioctl manages race_list.

Example 4-3 remedies the race conditions caused by race_ioctl by serializing its execution via the race_ioctl_mtx function. race_ioctl_mtx is defined as the d_ioctl function. It begins by acquiring race_mtx. Then race_ioctl is called and subsequently race_mtx is released.

As you can see, it takes just three lines (or one mutex) to serialize the execution of race_ioctl.