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.
9 #include <l4/shmc/shmc.h>
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>
21 #include <l4/util/util.h>
22 #include <l4/util/atomic.h>
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)
31 l4_umword_t lock; // lock for handling chunks
32 l4_addr_t _first_chunk; // offset to first chunk
36 SHMAREA_LOCK_FREE, SHMAREA_LOCK_TAKEN,
40 static inline l4shmc_chunk_desc_t *
41 chunk_get(l4_addr_t o, void *shm_local_addr)
43 return (l4shmc_chunk_desc_t *)(o + (l4_addr_t)shm_local_addr);
47 l4shmc_create(const char *shm_name, l4_umword_t shm_size)
50 l4re_ds_t shm_ds = L4_INVALID_CAP;
51 l4re_namespace_t tmp = L4_INVALID_CAP;
54 if (l4_is_invalid_cap(shm_ds = l4re_util_cap_alloc()))
57 if ((r = l4re_ma_alloc(shm_size, shm_ds, 0)))
60 if ((r = l4re_rm_attach((void **)&s, shm_size, L4RE_RM_SEARCH_ADDR, shm_ds,
67 if (l4_is_invalid_cap(tmp = l4re_util_cap_alloc()))
70 tmp = l4re_get_env_cap(shm_name);
71 if (l4_is_invalid_cap(tmp))
77 if ((r = l4re_ns_register_obj_srv(tmp, "shm", shm_ds, L4RE_NS_REGISTER_RW)))
80 l4re_rm_detach_unmap((l4_addr_t)s, L4RE_THIS_TASK_CAP);
85 if (!l4_is_invalid_cap(tmp))
86 l4re_util_cap_free(tmp);
92 l4shmc_attach_to(const char *shm_name, l4_umword_t timeout_ms,
93 l4shmc_area_t *shmarea)
96 l4re_namespace_t nssrv;
98 strncpy(shmarea->_name, shm_name, sizeof(shmarea->_name));
99 shmarea->_name[sizeof(shmarea->_name) - 1] = 0;
101 if (l4_is_invalid_cap(shmarea->_shm_ds = l4re_util_cap_alloc()))
104 nssrv = l4re_get_env_cap(shm_name);
105 if (l4_is_invalid_cap(nssrv))
107 printf("shm: did not find '%s' namespace\n", shm_name);
111 if ((r = l4re_ns_query_to_srv(nssrv, "shm", shmarea->_shm_ds, timeout_ms)))
113 printf("shm: did not find shm-ds 'shm' (%ld)\n", r);
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,
129 l4shmc_add_chunk(l4shmc_area_t *shmarea,
130 const char *chunk_name,
131 l4_umword_t chunk_capacity,
132 l4shmc_chunk_t *chunk)
134 shared_mem_t *shm_addr = (shared_mem_t *)shmarea->_local_addr;
136 l4shmc_chunk_desc_t *p;
137 l4shmc_chunk_desc_t *prev = NULL;
141 while (!l4util_cmpxchg(&shm_addr->lock, SHMAREA_LOCK_FREE,
144 asm volatile ("" : : : "memory");
148 if (shm_addr->_first_chunk)
150 offs = shm_addr->_first_chunk;
151 p = chunk_get(offs, shmarea->_local_addr);
154 offs = p->_offset + p->_capacity + sizeof(*p);
156 p = chunk_get(p->_next, shmarea->_local_addr);
161 // first chunk starts right after shm-header
162 offs = sizeof(shared_mem_t);
164 if ((shm_sz = l4shmc_area_size(shmarea)) < 0)
167 if (offs + chunk_capacity + sizeof(*p) >= (unsigned long)shm_sz)
168 return -L4_ENOMEM; // no more free memory in this shm
170 p = chunk_get(offs, shmarea->_local_addr);
173 p->_capacity = chunk_capacity;
178 shm_addr->_first_chunk = offs;
180 asm volatile ("" : : : "memory");
181 shm_addr->lock = SHMAREA_LOCK_FREE;
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;
190 chunk->_shm = shmarea;
197 l4shmc_add_signal(l4shmc_area_t *shmarea,
198 const char *signal_name,
199 l4shmc_signal_t *signal)
201 /* Now that the chunk is allocated in the shm, lets get the UIRQ
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))
210 if ((r = l4_error(l4_factory_create_irq(l4re_env()->factory,
214 snprintf(b, sizeof(b) - 1, "sig-%s", signal_name);
215 b[sizeof(b) - 1] = 0;
217 tmp = l4re_get_env_cap(shmarea->_name);
218 if (l4_is_invalid_cap(tmp))
221 if (l4re_ns_register_obj_srv(tmp, b, signal->_sigcap, 0))
223 l4re_util_cap_free(tmp);
227 l4re_util_cap_free(tmp);
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)
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;
243 l4_addr_t offs = shm_addr->_first_chunk;
246 l4shmc_chunk_desc_t *p;
247 p = chunk_get(offs, shmarea->_local_addr);
249 if (!strcmp(p->_name, chunk_name))
251 chunk->_shm = shmarea;
262 l4_sleep(100); // sleep 100ms
264 while (l4re_kip()->clock < try_until);
270 l4shmc_attach_signal_to(l4shmc_area_t *shmarea,
271 const char *signal_name,
273 l4_umword_t timeout_ms,
274 l4shmc_signal_t *signal)
278 r = l4shmc_get_signal_to(shmarea, signal_name, timeout_ms, signal);
282 if ((r = l4_error(l4_irq_attach(signal->_sigcap,
283 (l4_umword_t)signal, thread))))
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),
288 l4re_util_cap_free(signal->_sigcap);
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)
302 char b[L4SHMC_NAME_STRINGLEN + L4SHMC_SIGNAL_NAME_SIZE + 5]; // strings + "sig-"
305 signal->_sigcap = l4re_util_cap_alloc();
307 if (l4_is_invalid_cap(signal->_sigcap))
310 ns = l4re_get_env_cap(shmarea->_name);
311 if (l4_is_invalid_cap(ns))
314 snprintf(b, sizeof(b) - 1, "sig-%s", signal_name);
315 b[sizeof(b) - 1] = 0;
317 if (l4re_ns_query_to_srv(ns, b, signal->_sigcap, timeout_ms))
326 l4shmc_connect_chunk_signal(l4shmc_chunk_t *chunk,
327 l4shmc_signal_t *signal)
329 chunk->_sig = signal;
334 l4shmc_enable_signal(l4shmc_signal_t *s)
336 return l4_error(l4_irq_unmask(s->_sigcap));
340 l4shmc_enable_chunk(l4shmc_chunk_t *p)
342 return l4shmc_enable_signal(p->_sig);
346 l4shmc_wait_any_to(l4_timeout_t timeout, l4shmc_signal_t **p)
351 if ((r = l4_ipc_error(l4_ipc_wait(l4_utcb(), &l, timeout), l4_utcb())))
354 *p = (l4shmc_signal_t *)l;
360 l4shmc_wait_signal_to(l4shmc_signal_t *s, l4_timeout_t timeout)
364 if ((r = l4_ipc_error(l4_irq_receive(s->_sigcap, timeout), l4_utcb())))
371 l4shmc_wait_chunk_to(l4shmc_chunk_t *p, l4_timeout_t to)
373 return l4shmc_wait_signal_to(p->_sig, to);