/* * Copyright (C) 2013 Philippe Gerum . * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #ifndef _COBALT_UAPI_KERNEL_URW_H #define _COBALT_UAPI_KERNEL_URW_H #include /* * A restricted version of the kernel seqlocks with a slightly * different interface, allowing for unsynced reads with concurrent * write detection, without serializing writers. Caller should * provide for proper locking to deal with concurrent updates. * * urw_t lock = URW_INITIALIZER; * urwstate_t tmp; * * unsynced_read_block(&tmp, &lock) { * (will redo until clean read)... * } * * unsynced_write_block(&tmp, &lock) { * ... * } * * This code was inspired by Wolfgang Mauerer's linux/seqlock.h * adaptation for Xenomai 2.6 to support the VDSO feature. */ typedef struct { __u32 sequence; } urw_t; typedef struct { __u32 token; __u32 dirty; } urwstate_t; #define URW_INITIALIZER { 0 } #define DEFINE_URW(__name) urw_t __name = URW_INITIALIZER #ifndef READ_ONCE #define READ_ONCE ACCESS_ONCE #endif static inline void __try_read_start(const urw_t *urw, urwstate_t *tmp) { __u32 token; repeat: token = READ_ONCE(urw->sequence); smp_rmb(); if (token & 1) { cpu_relax(); goto repeat; } tmp->token = token; tmp->dirty = 1; } static inline void __try_read_end(const urw_t *urw, urwstate_t *tmp) { smp_rmb(); if (urw->sequence != tmp->token) { __try_read_start(urw, tmp); return; } tmp->dirty = 0; } static inline void __do_write_start(urw_t *urw, urwstate_t *tmp) { urw->sequence++; tmp->dirty = 1; smp_wmb(); } static inline void __do_write_end(urw_t *urw, urwstate_t *tmp) { smp_wmb(); tmp->dirty = 0; urw->sequence++; } static inline void unsynced_rw_init(urw_t *urw) { urw->sequence = 0; } #define unsynced_read_block(__tmp, __urw) \ for (__try_read_start(__urw, __tmp); \ (__tmp)->dirty; __try_read_end(__urw, __tmp)) #define unsynced_write_block(__tmp, __urw) \ for (__do_write_start(__urw, __tmp); \ (__tmp)->dirty; __do_write_end(__urw, __tmp)) #endif /* !_COBALT_UAPI_KERNEL_URW_H */