Xenomai  3.0.5
urw.h
1 /*
2  * Copyright (C) 2013 Philippe Gerum <rpm@xenomai.org>.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
17  */
18 #ifndef _COBALT_UAPI_KERNEL_URW_H
19 #define _COBALT_UAPI_KERNEL_URW_H
20 
21 #include <linux/types.h>
22 
23 /*
24  * A restricted version of the kernel seqlocks with a slightly
25  * different interface, allowing for unsynced reads with concurrent
26  * write detection, without serializing writers. Caller should
27  * provide for proper locking to deal with concurrent updates.
28  *
29  * urw_t lock = URW_INITIALIZER;
30  * urwstate_t tmp;
31  *
32  * unsynced_read_block(&tmp, &lock) {
33  * (will redo until clean read)...
34  * }
35  *
36  * unsynced_write_block(&tmp, &lock) {
37  * ...
38  * }
39  *
40  * This code was inspired by Wolfgang Mauerer's linux/seqlock.h
41  * adaptation for Xenomai 2.6 to support the VDSO feature.
42  */
43 
44 typedef struct {
45  __u32 sequence;
46 } urw_t;
47 
48 typedef struct {
49  __u32 token;
50  __u32 dirty;
51 } urwstate_t;
52 
53 #define URW_INITIALIZER { 0 }
54 #define DEFINE_URW(__name) urw_t __name = URW_INITIALIZER
55 
56 static inline void __try_read_start(const urw_t *urw, urwstate_t *tmp)
57 {
58  __u32 token;
59 repeat:
60  token = ACCESS_ONCE(urw->sequence);
61  smp_rmb();
62  if (token & 1) {
63  cpu_relax();
64  goto repeat;
65  }
66 
67  tmp->token = token;
68  tmp->dirty = 1;
69 }
70 
71 static inline void __try_read_end(const urw_t *urw, urwstate_t *tmp)
72 {
73  smp_rmb();
74  if (urw->sequence != tmp->token) {
75  __try_read_start(urw, tmp);
76  return;
77  }
78 
79  tmp->dirty = 0;
80 }
81 
82 static inline void __do_write_start(urw_t *urw, urwstate_t *tmp)
83 {
84  urw->sequence++;
85  tmp->dirty = 1;
86  smp_wmb();
87 }
88 
89 static inline void __do_write_end(urw_t *urw, urwstate_t *tmp)
90 {
91  smp_wmb();
92  tmp->dirty = 0;
93  urw->sequence++;
94 }
95 
96 static inline void unsynced_rw_init(urw_t *urw)
97 {
98  urw->sequence = 0;
99 }
100 
101 #define unsynced_read_block(__tmp, __urw) \
102  for (__try_read_start(__urw, __tmp); \
103  (__tmp)->dirty; __try_read_end(__urw, __tmp))
104 
105 #define unsynced_write_block(__tmp, __urw) \
106  for (__do_write_start(__urw, __tmp); \
107  (__tmp)->dirty; __do_write_end(__urw, __tmp))
108 
109 #endif /* !_COBALT_UAPI_KERNEL_URW_H */