1*1fb62fb0SOlivier Houchard /* 2*1fb62fb0SOlivier Houchard * Copyright 2010-2015 Samy Al Bahra. 3*1fb62fb0SOlivier Houchard * All rights reserved. 4*1fb62fb0SOlivier Houchard * 5*1fb62fb0SOlivier Houchard * Redistribution and use in source and binary forms, with or without 6*1fb62fb0SOlivier Houchard * modification, are permitted provided that the following conditions 7*1fb62fb0SOlivier Houchard * are met: 8*1fb62fb0SOlivier Houchard * 1. Redistributions of source code must retain the above copyright 9*1fb62fb0SOlivier Houchard * notice, this list of conditions and the following disclaimer. 10*1fb62fb0SOlivier Houchard * 2. Redistributions in binary form must reproduce the above copyright 11*1fb62fb0SOlivier Houchard * notice, this list of conditions and the following disclaimer in the 12*1fb62fb0SOlivier Houchard * documentation and/or other materials provided with the distribution. 13*1fb62fb0SOlivier Houchard * 14*1fb62fb0SOlivier Houchard * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15*1fb62fb0SOlivier Houchard * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16*1fb62fb0SOlivier Houchard * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17*1fb62fb0SOlivier Houchard * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18*1fb62fb0SOlivier Houchard * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19*1fb62fb0SOlivier Houchard * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20*1fb62fb0SOlivier Houchard * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21*1fb62fb0SOlivier Houchard * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22*1fb62fb0SOlivier Houchard * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23*1fb62fb0SOlivier Houchard * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24*1fb62fb0SOlivier Houchard * SUCH DAMAGE. 25*1fb62fb0SOlivier Houchard */ 26*1fb62fb0SOlivier Houchard 27*1fb62fb0SOlivier Houchard #ifndef CK_SEQUENCE_H 28*1fb62fb0SOlivier Houchard #define CK_SEQUENCE_H 29*1fb62fb0SOlivier Houchard 30*1fb62fb0SOlivier Houchard #include <ck_cc.h> 31*1fb62fb0SOlivier Houchard #include <ck_pr.h> 32*1fb62fb0SOlivier Houchard #include <ck_stdbool.h> 33*1fb62fb0SOlivier Houchard 34*1fb62fb0SOlivier Houchard struct ck_sequence { 35*1fb62fb0SOlivier Houchard unsigned int sequence; 36*1fb62fb0SOlivier Houchard }; 37*1fb62fb0SOlivier Houchard typedef struct ck_sequence ck_sequence_t; 38*1fb62fb0SOlivier Houchard 39*1fb62fb0SOlivier Houchard #define CK_SEQUENCE_INITIALIZER { .sequence = 0 } 40*1fb62fb0SOlivier Houchard 41*1fb62fb0SOlivier Houchard CK_CC_INLINE static void 42*1fb62fb0SOlivier Houchard ck_sequence_init(struct ck_sequence *sq) 43*1fb62fb0SOlivier Houchard { 44*1fb62fb0SOlivier Houchard 45*1fb62fb0SOlivier Houchard ck_pr_store_uint(&sq->sequence, 0); 46*1fb62fb0SOlivier Houchard return; 47*1fb62fb0SOlivier Houchard } 48*1fb62fb0SOlivier Houchard 49*1fb62fb0SOlivier Houchard CK_CC_INLINE static unsigned int 50*1fb62fb0SOlivier Houchard ck_sequence_read_begin(const struct ck_sequence *sq) 51*1fb62fb0SOlivier Houchard { 52*1fb62fb0SOlivier Houchard unsigned int version; 53*1fb62fb0SOlivier Houchard 54*1fb62fb0SOlivier Houchard for (;;) { 55*1fb62fb0SOlivier Houchard version = ck_pr_load_uint(&sq->sequence); 56*1fb62fb0SOlivier Houchard 57*1fb62fb0SOlivier Houchard /* 58*1fb62fb0SOlivier Houchard * If a sequence is even then associated data may be in a 59*1fb62fb0SOlivier Houchard * consistent state. 60*1fb62fb0SOlivier Houchard */ 61*1fb62fb0SOlivier Houchard if (CK_CC_LIKELY((version & 1) == 0)) 62*1fb62fb0SOlivier Houchard break; 63*1fb62fb0SOlivier Houchard 64*1fb62fb0SOlivier Houchard /* 65*1fb62fb0SOlivier Houchard * If a sequence is odd then a thread is in the middle of an 66*1fb62fb0SOlivier Houchard * update. Retry the read to avoid operating on inconsistent 67*1fb62fb0SOlivier Houchard * data. 68*1fb62fb0SOlivier Houchard */ 69*1fb62fb0SOlivier Houchard ck_pr_stall(); 70*1fb62fb0SOlivier Houchard } 71*1fb62fb0SOlivier Houchard 72*1fb62fb0SOlivier Houchard ck_pr_fence_load(); 73*1fb62fb0SOlivier Houchard return version; 74*1fb62fb0SOlivier Houchard } 75*1fb62fb0SOlivier Houchard 76*1fb62fb0SOlivier Houchard CK_CC_INLINE static bool 77*1fb62fb0SOlivier Houchard ck_sequence_read_retry(const struct ck_sequence *sq, unsigned int version) 78*1fb62fb0SOlivier Houchard { 79*1fb62fb0SOlivier Houchard 80*1fb62fb0SOlivier Houchard /* 81*1fb62fb0SOlivier Houchard * If the sequence number was updated then a read should be 82*1fb62fb0SOlivier Houchard * re-attempted. 83*1fb62fb0SOlivier Houchard */ 84*1fb62fb0SOlivier Houchard ck_pr_fence_load(); 85*1fb62fb0SOlivier Houchard return ck_pr_load_uint(&sq->sequence) != version; 86*1fb62fb0SOlivier Houchard } 87*1fb62fb0SOlivier Houchard 88*1fb62fb0SOlivier Houchard #define CK_SEQUENCE_READ(seqlock, version) \ 89*1fb62fb0SOlivier Houchard for (*(version) = 1; \ 90*1fb62fb0SOlivier Houchard (*(version) != 0) && (*(version) = ck_sequence_read_begin(seqlock), 1); \ 91*1fb62fb0SOlivier Houchard *(version) = ck_sequence_read_retry(seqlock, *(version))) 92*1fb62fb0SOlivier Houchard 93*1fb62fb0SOlivier Houchard /* 94*1fb62fb0SOlivier Houchard * This must be called after a successful mutex acquisition. 95*1fb62fb0SOlivier Houchard */ 96*1fb62fb0SOlivier Houchard CK_CC_INLINE static void 97*1fb62fb0SOlivier Houchard ck_sequence_write_begin(struct ck_sequence *sq) 98*1fb62fb0SOlivier Houchard { 99*1fb62fb0SOlivier Houchard 100*1fb62fb0SOlivier Houchard /* 101*1fb62fb0SOlivier Houchard * Increment the sequence to an odd number to indicate 102*1fb62fb0SOlivier Houchard * the beginning of a write update. 103*1fb62fb0SOlivier Houchard */ 104*1fb62fb0SOlivier Houchard ck_pr_store_uint(&sq->sequence, sq->sequence + 1); 105*1fb62fb0SOlivier Houchard ck_pr_fence_store(); 106*1fb62fb0SOlivier Houchard return; 107*1fb62fb0SOlivier Houchard } 108*1fb62fb0SOlivier Houchard 109*1fb62fb0SOlivier Houchard /* 110*1fb62fb0SOlivier Houchard * This must be called before mutex ownership is relinquished. 111*1fb62fb0SOlivier Houchard */ 112*1fb62fb0SOlivier Houchard CK_CC_INLINE static void 113*1fb62fb0SOlivier Houchard ck_sequence_write_end(struct ck_sequence *sq) 114*1fb62fb0SOlivier Houchard { 115*1fb62fb0SOlivier Houchard 116*1fb62fb0SOlivier Houchard /* 117*1fb62fb0SOlivier Houchard * Increment the sequence to an even number to indicate 118*1fb62fb0SOlivier Houchard * completion of a write update. 119*1fb62fb0SOlivier Houchard */ 120*1fb62fb0SOlivier Houchard ck_pr_fence_store(); 121*1fb62fb0SOlivier Houchard ck_pr_store_uint(&sq->sequence, sq->sequence + 1); 122*1fb62fb0SOlivier Houchard return; 123*1fb62fb0SOlivier Houchard } 124*1fb62fb0SOlivier Houchard 125*1fb62fb0SOlivier Houchard #endif /* CK_SEQUENCE_H */ 126