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