hc
2024-11-01 2f529f9b558ca1c1bd74be7437a84e4711743404
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
/*
 * Copyright (C) 2007 Philippe Gerum <rpm@xenomai.org>.
 *
 * Xenomai is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * Xenomai 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
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Xenomai; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 * 02111-1307, USA.
 */
#include <linux/module.h>
#include <cobalt/kernel/heap.h>
#include <cobalt/kernel/map.h>
#include <asm/xenomai/machine.h>
 
/**
 * @ingroup cobalt_core
 * @defgroup cobalt_core_map Lightweight key-to-object mapping service
 *
 * A map is a simple indexing structure which associates unique
 * integer keys with pointers to objects.  The current implementation
 * supports reservation, for naming/indexing objects, either on a
 * fixed, user-provided integer (i.e. a reserved key value), or by
 * drawing the next available key internally if the caller did not
 * specify any fixed key. For instance, in some given map, the key
 * space ranging from 0 to 255 could be reserved for fixed keys,
 * whilst the range from 256 to 511 could be available for drawing
 * free keys dynamically.
 *
 * A maximum of 1024 unique keys per map is supported on 32bit
 * machines.
 *
 * (This implementation should not be confused with C++ STL maps,
 * which are dynamically expandable and allow arbitrary key types;
 * Xenomai maps don't).
 *
 * @{
 */
 
/**
 * @fn void xnmap_create(int nkeys, int reserve, int offset)
 * @brief Create a map.
 *
 * Allocates a new map with the specified addressing capabilities. The
 * memory is obtained from the Xenomai system heap.
 *
 * @param nkeys The maximum number of unique keys the map will be able
 * to hold. This value cannot exceed the static limit represented by
 * XNMAP_MAX_KEYS, and must be a power of two.
 *
 * @param reserve The number of keys which should be kept for
 * reservation within the index space. Reserving a key means to
 * specify a valid key to the xnmap_enter() service, which will then
 * attempt to register this exact key, instead of drawing the next
 * available key from the unreserved index space. When reservation is
 * in effect, the unreserved index space will hold key values greater
 * than @a reserve, keeping the low key values for the reserved space.
 * For instance, passing @a reserve = 32 would cause the index range [
 * 0 .. 31 ] to be kept for reserved keys.  When non-zero, @a reserve
 * is rounded to the next multiple of BITS_PER_LONG. If @a reserve is
 * zero no reservation will be available from the map.
 *
 * @param offset The lowest key value xnmap_enter() will return to the
 * caller. Key values will be in the range [ 0 + offset .. @a nkeys +
 * offset - 1 ]. Negative offsets are valid.
 *
 * @return the address of the new map is returned on success;
 * otherwise, NULL is returned if @a nkeys is invalid.
 *
 * @coretags{task-unrestricted}
 */
struct xnmap *xnmap_create(int nkeys, int reserve, int offset)
{
   struct xnmap *map;
   int mapsize;
 
   if (nkeys <= 0 || (nkeys & (nkeys - 1)) != 0)
       return NULL;
 
   mapsize = sizeof(*map) + (nkeys - 1) * sizeof(map->objarray[0]);
   map = xnmalloc(mapsize);
 
   if (!map)
       return NULL;
 
   map->ukeys = 0;
   map->nkeys = nkeys;
   map->offset = offset;
   map->himask = (1 << ((reserve + BITS_PER_LONG - 1) / BITS_PER_LONG)) - 1;
   map->himap = ~0;
   memset(map->lomap, ~0, sizeof(map->lomap));
   memset(map->objarray, 0, sizeof(map->objarray[0]) * nkeys);
 
   return map;
}
EXPORT_SYMBOL_GPL(xnmap_create);
 
/**
 * @fn void xnmap_delete(struct xnmap *map)
 * @brief Delete a map.
 *
 * Deletes a map, freeing any associated memory back to the Xenomai
 * system heap.
 *
 * @param map The address of the map to delete.
 *
 * @coretags{task-unrestricted}
 */
void xnmap_delete(struct xnmap *map)
{
   xnfree(map);
}
EXPORT_SYMBOL_GPL(xnmap_delete);
 
/**
 * @fn void xnmap_enter(struct xnmap *map, int key, void *objaddr)
 * @brief Index an object into a map.
 *
 * Insert a new object into the given map.
 *
 * @param map The address of the map to insert into.
 *
 * @param key The key to index the object on. If this key is within
 * the valid index range [ 0 - offset .. nkeys - offset - 1 ], then an
 * attempt to reserve this exact key is made. If @a key has an
 * out-of-range value lower or equal to 0 - offset - 1, then an
 * attempt is made to draw a free key from the unreserved index space.
 *
 * @param objaddr The address of the object to index on the key. This
 * value will be returned by a successful call to xnmap_fetch() with
 * the same key.
 *
 * @return a valid key is returned on success, either @a key if
 * reserved, or the next free key. Otherwise:
 *
 * - -EEXIST is returned upon attempt to reserve a busy key.
 *
 * - -ENOSPC when no more free key is available.
 *
 * @coretags{unrestricted}
 */
int xnmap_enter(struct xnmap *map, int key, void *objaddr)
{
   int hi, lo, ofkey = key - map->offset;
   spl_t s;
 
   xnlock_get_irqsave(&nklock, s);
 
   if (ofkey >= 0 && ofkey < map->nkeys) {
       if (map->objarray[ofkey] != NULL) {
           key = -EEXIST;
           goto unlock_and_exit;
       }
   } else if (map->ukeys >= map->nkeys) {
       key = -ENOSPC;
       goto unlock_and_exit;
   }
   else {
       /* The himask implements a namespace reservation of
          half of the bitmap space which cannot be used to
          draw keys. */
 
       hi = ffnz(map->himap & ~map->himask);
       lo = ffnz(map->lomap[hi]);
       ofkey = hi * BITS_PER_LONG + lo;
       ++map->ukeys;
 
       map->lomap[hi] &= ~(1UL << lo);
       if (map->lomap[hi] == 0)
           map->himap &= ~(1UL << hi);
   }
 
   map->objarray[ofkey] = objaddr;
 
      unlock_and_exit:
 
   xnlock_put_irqrestore(&nklock, s);
 
   return ofkey + map->offset;
}
EXPORT_SYMBOL_GPL(xnmap_enter);
 
/**
 * @fn void xnmap_remove(struct xnmap *map, int key)
 * @brief Remove an object reference from a map.
 *
 * Removes an object reference from the given map, releasing the
 * associated key.
 *
 * @param map The address of the map to remove from.
 *
 * @param key The key the object reference to be removed is indexed
 * on.
 *
 * @return 0 is returned on success. Otherwise:
 *
 * - -ESRCH is returned if @a key is invalid.
 *
 * @coretags{unrestricted}
 */
int xnmap_remove(struct xnmap *map, int key)
{
   int ofkey = key - map->offset, hi, lo;
   spl_t s;
 
   if (ofkey < 0 || ofkey >= map->nkeys)
       return -ESRCH;
 
   hi = ofkey / BITS_PER_LONG;
   lo = ofkey % BITS_PER_LONG;
   xnlock_get_irqsave(&nklock, s);
   map->objarray[ofkey] = NULL;
   map->himap |= (1UL << hi);
   map->lomap[hi] |= (1UL << lo);
   --map->ukeys;
   xnlock_put_irqrestore(&nklock, s);
 
   return 0;
}
EXPORT_SYMBOL_GPL(xnmap_remove);
 
/**
 * @fn void xnmap_fetch(struct xnmap *map, int key)
 * @brief Search an object into a map.
 *
 * Retrieve an object reference from the given map by its index key.
 *
 * @param map The address of the map to retrieve from.
 *
 * @param key The key to be searched for in the map index.
 *
 * @return The indexed object address is returned on success,
 * otherwise NULL is returned when @a key is invalid or no object is
 * currently indexed on it.
 *
 * @coretags{unrestricted}
 */
 
/**
 * @fn void xnmap_fetch_nocheck(struct xnmap *map, int key)
 * @brief Search an object into a map - unchecked form.
 *
 * Retrieve an object reference from the given map by its index key,
 * but does not perform any sanity check on the provided key.
 *
 * @param map The address of the map to retrieve from.
 *
 * @param key The key to be searched for in the map index.
 *
 * @return The indexed object address is returned on success,
 * otherwise NULL is returned when no object is currently indexed on
 * @a key.
 *
 * @coretags{unrestricted}
 */
 
/** @} */