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