]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/shmc/lib/src/shmc.c
6ff84d52be140993de7090571845b4ed399d6ad5
[l4.git] / l4 / pkg / shmc / lib / src / shmc.c
1 /*
2  * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
3  *               Alexander Warg <warg@os.inf.tu-dresden.de>
4  *     economic rights: Technische Universität Dresden (Germany)
5  * This file is part of TUD:OS and distributed under the terms of the
6  * GNU Lesser General Public License 2.1.
7  * Please see the COPYING-LGPL-2.1 file for details.
8  */
9 #include <l4/shmc/shmc.h>
10
11 #include <l4/sys/err.h>
12 #include <l4/sys/factory.h>
13 #include <l4/sys/task.h>
14 #include <l4/re/env.h>
15 #include <l4/re/c/util/cap_alloc.h>
16 #include <l4/re/c/rm.h>
17 #include <l4/re/c/mem_alloc.h>
18 #include <l4/re/c/namespace.h>
19 #include <l4/sys/debugger.h>
20
21 #include <l4/util/util.h>
22 #include <l4/util/atomic.h>
23
24 #include <string.h>
25 #include <stdio.h>
26
27 /* Head of a shared memory data memory, which has a size of multiple pages
28  * No task local data must be in here (pointers, caps)
29  */
30 typedef struct {
31   l4_umword_t  lock;         // lock for handling chunks
32   l4_addr_t    _first_chunk; // offset to first chunk
33 } shared_mem_t;
34
35 enum {
36   SHMAREA_LOCK_FREE, SHMAREA_LOCK_TAKEN,
37 };
38
39
40 static inline l4shmc_chunk_desc_t *
41 chunk_get(l4_addr_t o, void *shm_local_addr)
42 {
43   return (l4shmc_chunk_desc_t *)(o + (l4_addr_t)shm_local_addr);
44 }
45
46 L4_CV long
47 l4shmc_create(const char *shm_name, l4_umword_t shm_size)
48 {
49   shared_mem_t *s;
50   l4re_ds_t shm_ds = L4_INVALID_CAP;
51   l4re_namespace_t tmp = L4_INVALID_CAP;
52   long r = -L4_ENOMEM;
53
54   if (l4_is_invalid_cap(shm_ds = l4re_util_cap_alloc()))
55     goto out;
56
57   if ((r = l4re_ma_alloc(shm_size, shm_ds, 0)))
58     goto out;
59
60   if ((r = l4re_rm_attach((void **)&s, shm_size, L4RE_RM_SEARCH_ADDR, shm_ds,
61                           0, L4_PAGESHIFT)))
62     goto out;
63
64   s->_first_chunk = 0;
65
66   r =  -L4_ENOMEM;
67   if (l4_is_invalid_cap(tmp = l4re_util_cap_alloc()))
68     goto out;
69
70   tmp = l4re_get_env_cap(shm_name);
71   if (l4_is_invalid_cap(tmp))
72     {
73       r = -L4_ENOENT;
74       goto out;
75     }
76
77   if ((r = l4re_ns_register_obj_srv(tmp, "shm", shm_ds, L4RE_NS_REGISTER_RW)))
78     goto out;
79
80   l4re_rm_detach_unmap((l4_addr_t)s, L4RE_THIS_TASK_CAP);
81
82   r = L4_EOK;
83
84 out:
85   if (!l4_is_invalid_cap(tmp))
86     l4re_util_cap_free(tmp);
87   return r;
88 }
89
90
91 L4_CV long
92 l4shmc_attach_to(const char *shm_name, l4_umword_t timeout_ms,
93                  l4shmc_area_t *shmarea)
94 {
95   long r;
96   l4re_namespace_t nssrv;
97
98   strncpy(shmarea->_name, shm_name, sizeof(shmarea->_name));
99   shmarea->_name[sizeof(shmarea->_name) - 1] = 0;
100
101   if (l4_is_invalid_cap(shmarea->_shm_ds = l4re_util_cap_alloc()))
102     return -L4_ENOMEM;
103
104   nssrv = l4re_get_env_cap(shm_name);
105   if (l4_is_invalid_cap(nssrv))
106     {
107       printf("shm: did not find '%s' namespace\n", shm_name);
108       return -L4_ENOENT;
109     }
110
111   if ((r = l4re_ns_query_to_srv(nssrv, "shm", shmarea->_shm_ds, timeout_ms)))
112     {
113       printf("shm: did not find shm-ds 'shm' (%ld)\n", r);
114       return -L4_ENOENT;
115     }
116
117   shmarea->_local_addr = 0;
118   if ((r = l4re_rm_attach(&shmarea->_local_addr,
119                           l4shmc_area_size(shmarea),
120                           L4RE_RM_SEARCH_ADDR, shmarea->_shm_ds,
121                           0, L4_PAGESHIFT)))
122     return r;
123
124   return L4_EOK;
125 }
126
127
128 L4_CV long
129 l4shmc_add_chunk(l4shmc_area_t *shmarea,
130                 const char *chunk_name,
131                 l4_umword_t chunk_capacity,
132                 l4shmc_chunk_t *chunk)
133 {
134   shared_mem_t *shm_addr = (shared_mem_t *)shmarea->_local_addr;
135
136   l4shmc_chunk_desc_t *p;
137   l4shmc_chunk_desc_t *prev = NULL;
138
139   shm_addr->lock = 0;
140
141   while (!l4util_cmpxchg(&shm_addr->lock, SHMAREA_LOCK_FREE,
142                          SHMAREA_LOCK_TAKEN))
143     l4_sleep(1);
144   asm volatile ("" : : : "memory");
145   {
146     l4_addr_t offs;
147     long shm_sz;
148     if (shm_addr->_first_chunk)
149       {
150         offs = shm_addr->_first_chunk;
151         p = chunk_get(offs, shmarea->_local_addr);
152         do
153           {
154             offs = p->_offset + p->_capacity + sizeof(*p);
155             prev = p;
156             p = chunk_get(p->_next, shmarea->_local_addr);
157           }
158         while (prev->_next);
159       }
160     else
161       // first chunk starts right after shm-header
162       offs = sizeof(shared_mem_t);
163
164     if ((shm_sz = l4shmc_area_size(shmarea)) < 0)
165       return -L4_ENOMEM;
166
167     if (offs + chunk_capacity + sizeof(*p) >= (unsigned long)shm_sz)
168       return -L4_ENOMEM; // no more free memory in this shm
169
170     p = chunk_get(offs, shmarea->_local_addr);
171     p->_offset = offs;
172     p->_next = 0;
173     p->_capacity = chunk_capacity;
174
175     if (prev)
176       prev->_next = offs;
177     else
178       shm_addr->_first_chunk = offs;
179   }
180   asm volatile ("" : : : "memory");
181   shm_addr->lock = SHMAREA_LOCK_FREE;
182
183   p->_size = 0;
184   p->_status = L4SHMC_CHUNK_CLEAR;
185   p->_magic = L4SHMC_CHUNK_MAGIC;
186   strncpy(p->_name, chunk_name, sizeof(p->_name));
187   p->_name[sizeof(p->_name) - 1] = 0;
188
189   chunk->_chunk = p;
190   chunk->_shm    = shmarea;
191   chunk->_sig    = NULL;
192
193   return L4_EOK;
194 }
195
196 L4_CV long
197 l4shmc_add_signal(l4shmc_area_t *shmarea,
198                  const char *signal_name,
199                  l4shmc_signal_t *signal)
200 {
201   /* Now that the chunk is allocated in the shm, lets get the UIRQ
202    * and register it */
203   long r;
204   l4re_namespace_t tmp;
205   char b[L4SHMC_NAME_STRINGLEN + L4SHMC_SIGNAL_NAME_SIZE + 5]; // strings + "sig-"
206   signal->_sigcap = l4re_util_cap_alloc();
207   if (l4_is_invalid_cap(signal->_sigcap))
208     return -L4_ENOMEM;
209
210   if ((r = l4_error(l4_factory_create_irq(l4re_env()->factory,
211                                           signal->_sigcap))))
212     return r;
213
214   snprintf(b, sizeof(b) - 1, "sig-%s", signal_name);
215   b[sizeof(b) - 1] = 0;
216
217   tmp = l4re_get_env_cap(shmarea->_name);
218   if (l4_is_invalid_cap(tmp))
219     return -L4_ENOENT;
220
221   if (l4re_ns_register_obj_srv(tmp, b, signal->_sigcap, 0))
222     {
223       l4re_util_cap_free(tmp);
224       return -L4_ENOENT;
225     }
226
227   l4re_util_cap_free(tmp);
228
229   return L4_EOK;
230 }
231
232 L4_CV long
233 l4shmc_get_chunk_to(l4shmc_area_t *shmarea,
234                     const char *chunk_name,
235                     l4_umword_t timeout_ms,
236                     l4shmc_chunk_t *chunk)
237 {
238   l4_kernel_clock_t try_until = l4re_kip()->clock + (timeout_ms * 1000);
239   shared_mem_t *shm_addr = (shared_mem_t *)shmarea->_local_addr;
240
241   do
242     {
243       l4_addr_t offs = shm_addr->_first_chunk;
244       while (offs)
245         {
246           l4shmc_chunk_desc_t *p;
247           p = chunk_get(offs, shmarea->_local_addr);
248
249           if (!strcmp(p->_name, chunk_name))
250             { // found it!
251                chunk->_shm    = shmarea;
252                chunk->_chunk = p;
253                chunk->_sig    = NULL;
254                return L4_EOK;
255             }
256           offs = p->_next;
257         }
258
259       if (!timeout_ms)
260         break;
261
262       l4_sleep(100); // sleep 100ms
263     }
264   while (l4re_kip()->clock < try_until);
265
266   return -L4_ENOENT;
267 }
268
269 L4_CV long
270 l4shmc_attach_signal_to(l4shmc_area_t *shmarea,
271                        const char *signal_name,
272                        l4_cap_idx_t thread,
273                        l4_umword_t timeout_ms,
274                        l4shmc_signal_t *signal)
275 {
276   long r = L4_EOK;
277
278   r = l4shmc_get_signal_to(shmarea, signal_name, timeout_ms, signal);
279   if (r)
280     goto out;
281
282   if ((r = l4_error(l4_irq_attach(signal->_sigcap,
283                                   (l4_umword_t)signal, thread))))
284     {
285       printf("Error on irq_attach(): %ld (sigcap %lx, sig_id %lx, thread %lx\n",
286              r, signal->_sigcap, l4_debugger_global_id(signal->_sigcap),
287              thread);
288       l4re_util_cap_free(signal->_sigcap);
289       goto out;
290     }
291
292 out:
293   return r;
294 }
295
296 L4_CV long
297 l4shmc_get_signal_to(l4shmc_area_t *shmarea,
298                     const char *signal_name,
299                     l4_umword_t timeout_ms,
300                     l4shmc_signal_t *signal)
301 {
302   char b[L4SHMC_NAME_STRINGLEN + L4SHMC_SIGNAL_NAME_SIZE + 5]; // strings + "sig-"
303   l4re_namespace_t ns;
304
305   signal->_sigcap = l4re_util_cap_alloc();
306
307   if (l4_is_invalid_cap(signal->_sigcap))
308     return -L4_ENOMEM;
309
310   ns = l4re_get_env_cap(shmarea->_name);
311   if (l4_is_invalid_cap(ns))
312     return -L4_ENOENT;
313
314   snprintf(b, sizeof(b) - 1, "sig-%s", signal_name);
315   b[sizeof(b) - 1] = 0;
316
317   if (l4re_ns_query_to_srv(ns, b, signal->_sigcap, timeout_ms))
318     return -L4_ENOENT;
319
320   return L4_EOK;
321 }
322
323
324
325 L4_CV long
326 l4shmc_connect_chunk_signal(l4shmc_chunk_t *chunk,
327                             l4shmc_signal_t *signal)
328 {
329   chunk->_sig = signal;
330   return L4_EOK;
331 }
332
333 L4_CV long
334 l4shmc_enable_signal(l4shmc_signal_t *s)
335 {
336   return l4_error(l4_irq_unmask(s->_sigcap));
337 }
338
339 L4_CV long
340 l4shmc_enable_chunk(l4shmc_chunk_t *p)
341 {
342   return l4shmc_enable_signal(p->_sig);
343 }
344
345 L4_CV long
346 l4shmc_wait_any_to(l4_timeout_t timeout, l4shmc_signal_t **p)
347 {
348   l4_umword_t l;
349   long r;
350
351   if ((r = l4_ipc_error(l4_ipc_wait(l4_utcb(), &l, timeout), l4_utcb())))
352     return r;
353
354   *p = (l4shmc_signal_t *)l;
355
356   return L4_EOK;
357 }
358
359 L4_CV long
360 l4shmc_wait_signal_to(l4shmc_signal_t *s, l4_timeout_t timeout)
361 {
362   long r;
363
364   if ((r = l4_ipc_error(l4_irq_receive(s->_sigcap, timeout), l4_utcb())))
365     return r;
366
367   return L4_EOK;
368 }
369
370 L4_CV long
371 l4shmc_wait_chunk_to(l4shmc_chunk_t *p, l4_timeout_t to)
372 {
373   return l4shmc_wait_signal_to(p->_sig, to);
374 }