1 /*
   2  * This file and its contents are supplied under the terms of the
   3  * Common Development and Distribution License ("CDDL"), version 1.0.
   4  * You may only use this file in accordance with the terms of version
   5  * 1.0 of the CDDL.
   6  *
   7  * A full copy of the text of the CDDL should have accompanied this
   8  * source.  A copy of the CDDL is also available via the Internet at
   9  * http://www.illumos.org/license/CDDL.
  10  */
  11 /*
  12  * Copyright 2012 Nexenta Systems, Inc.  All rights reserved.
  13  *
  14  * seqlock.c - Implementation of sequence lock algorithm.
  15  */
  16 #include <sys/types.h>
  17 #include <sys/ddi.h>
  18 #include <sys/mutex.h>
  19 #include <sys/cpu.h>              /* for SMT_PAUSE */
  20 #include <sys/cpuvar.h>           /* for kpreempt */
  21 #include <sys/seqlock.h>
  22 
  23 void
  24 seq_init(seqlock_t *seqlock)
  25 {
  26         seqlock->sequence = 0;
  27         mutex_init(&seqlock->lock, NULL, MUTEX_DEFAULT, NULL);
  28 }
  29 
  30 void
  31 seq_destroy(seqlock_t *seqlock)
  32 {
  33         mutex_destroy(&seqlock->lock);
  34 }
  35 
  36 int
  37 seq_read_begin(volatile seqlock_t *seqlock)
  38 {
  39         int seq;
  40 again:
  41         seq = seqlock->sequence;
  42         if (seq & 0x1) {
  43                 SMT_PAUSE();
  44                 goto again;
  45         }
  46         membar_consumer();
  47         return (seq);
  48 }
  49 
  50 void
  51 seq_write_lock(seqlock_t *seqlock)
  52 {
  53         mutex_enter(&seqlock->lock);
  54         kpreempt_disable();
  55         seqlock->sequence++;
  56         membar_producer();
  57 }
  58 
  59 void
  60 seq_write_unlock(seqlock_t *seqlock)
  61 {
  62         seqlock->sequence++;
  63         membar_producer();
  64         kpreempt_enable();
  65         mutex_exit(&seqlock->lock);
  66 }