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 shm_cap;
54 shm_cap = l4re_get_env_cap(shm_name);
55 if (l4_is_invalid_cap(shm_cap))
58 if (l4_is_invalid_cap(shm_ds = l4re_util_cap_alloc()))
61 if ((r = l4re_ma_alloc(shm_size, shm_ds, 0)))
62 goto out_shm_free_cap;
64 if ((r = l4re_rm_attach((void **)&s, shm_size, L4RE_RM_SEARCH_ADDR, shm_ds,
66 goto out_shm_free_mem;
71 if ((r = l4re_ns_register_obj_srv(shm_cap, "shm", shm_ds, L4RE_NS_REGISTER_RW)))
74 l4re_rm_detach_unmap((l4_addr_t)s, L4RE_THIS_TASK_CAP);
81 l4re_util_cap_free(shm_ds);
87 l4shmc_attach_to(const char *shm_name, l4_umword_t timeout_ms,
88 l4shmc_area_t *shmarea)
91 l4re_namespace_t nssrv;
93 strncpy(shmarea->_name, shm_name, sizeof(shmarea->_name));
94 shmarea->_name[sizeof(shmarea->_name) - 1] = 0;
96 if (l4_is_invalid_cap(shmarea->_shm_ds = l4re_util_cap_alloc()))
99 nssrv = l4re_get_env_cap(shm_name);
100 if (l4_is_invalid_cap(nssrv))
102 printf("shm: did not find '%s' namespace\n", shm_name);
106 if ((r = l4re_ns_query_to_srv(nssrv, "shm", shmarea->_shm_ds, timeout_ms)))
108 printf("shm: did not find shm-ds 'shm' (%ld)\n", r);
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,
124 l4shmc_add_chunk(l4shmc_area_t *shmarea,
125 const char *chunk_name,
126 l4_umword_t chunk_capacity,
127 l4shmc_chunk_t *chunk)
129 shared_mem_t *shm_addr = (shared_mem_t *)shmarea->_local_addr;
131 l4shmc_chunk_desc_t *p;
132 l4shmc_chunk_desc_t *prev = NULL;
136 while (!l4util_cmpxchg(&shm_addr->lock, SHMAREA_LOCK_FREE,
139 asm volatile ("" : : : "memory");
143 if (shm_addr->_first_chunk)
145 offs = shm_addr->_first_chunk;
146 p = chunk_get(offs, shmarea->_local_addr);
149 offs = p->_offset + p->_capacity + sizeof(*p);
151 p = chunk_get(p->_next, shmarea->_local_addr);
156 // first chunk starts right after shm-header
157 offs = sizeof(shared_mem_t);
159 if ((shm_sz = l4shmc_area_size(shmarea)) < 0)
162 if (offs + chunk_capacity + sizeof(*p) >= (unsigned long)shm_sz)
163 return -L4_ENOMEM; // no more free memory in this shm
165 p = chunk_get(offs, shmarea->_local_addr);
168 p->_capacity = chunk_capacity;
173 shm_addr->_first_chunk = offs;
175 asm volatile ("" : : : "memory");
176 shm_addr->lock = SHMAREA_LOCK_FREE;
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;
185 chunk->_shm = shmarea;
192 l4shmc_add_signal(l4shmc_area_t *shmarea,
193 const char *signal_name,
194 l4shmc_signal_t *signal)
196 /* Now that the chunk is allocated in the shm, lets get the UIRQ
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))
205 if ((r = l4_error(l4_factory_create_irq(l4re_env()->factory,
209 snprintf(b, sizeof(b) - 1, "sig-%s", signal_name);
210 b[sizeof(b) - 1] = 0;
212 tmp = l4re_get_env_cap(shmarea->_name);
213 if (l4_is_invalid_cap(tmp))
216 if (l4re_ns_register_obj_srv(tmp, b, signal->_sigcap, 0))
218 l4re_util_cap_free(tmp);
222 l4re_util_cap_free(tmp);
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)
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;
238 l4_addr_t offs = shm_addr->_first_chunk;
241 l4shmc_chunk_desc_t *p;
242 p = chunk_get(offs, shmarea->_local_addr);
244 if (!strcmp(p->_name, chunk_name))
246 chunk->_shm = shmarea;
257 l4_sleep(100); // sleep 100ms
259 while (l4re_kip()->clock < try_until);
265 l4shmc_attach_signal_to(l4shmc_area_t *shmarea,
266 const char *signal_name,
268 l4_umword_t timeout_ms,
269 l4shmc_signal_t *signal)
273 r = l4shmc_get_signal_to(shmarea, signal_name, timeout_ms, signal);
277 if ((r = l4_error(l4_irq_attach(signal->_sigcap,
278 (l4_umword_t)signal, thread))))
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),
283 l4re_util_cap_free(signal->_sigcap);
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)
296 char b[L4SHMC_NAME_STRINGLEN + L4SHMC_SIGNAL_NAME_SIZE + 5]; // strings + "sig-"
298 l4_cpu_time_t timeout;
300 signal->_sigcap = l4re_util_cap_alloc();
302 if (l4_is_invalid_cap(signal->_sigcap))
305 ns = l4re_get_env_cap(shmarea->_name);
306 if (l4_is_invalid_cap(ns))
309 snprintf(b, sizeof(b) - 1, "sig-%s", signal_name);
310 b[sizeof(b) - 1] = 0;
312 timeout = l4re_kip()->clock + timeout_ms * 1000;
315 int e = l4re_ns_query_to_srv(ns, b, signal->_sigcap, timeout_ms);
318 if (l4re_kip()->clock < timeout)
330 l4shmc_connect_chunk_signal(l4shmc_chunk_t *chunk,
331 l4shmc_signal_t *signal)
333 chunk->_sig = signal;
338 l4shmc_enable_signal(l4shmc_signal_t *s)
340 return l4_error(l4_irq_unmask(s->_sigcap));
344 l4shmc_enable_chunk(l4shmc_chunk_t *p)
346 return l4shmc_enable_signal(p->_sig);
350 l4shmc_wait_any_to(l4_timeout_t timeout, l4shmc_signal_t **p)
355 if ((r = l4_ipc_error(l4_ipc_wait(l4_utcb(), &l, timeout), l4_utcb())))
358 *p = (l4shmc_signal_t *)l;
364 l4shmc_wait_signal_to(l4shmc_signal_t *s, l4_timeout_t timeout)
368 if ((r = l4_ipc_error(l4_irq_receive(s->_sigcap, timeout), l4_utcb())))
375 l4shmc_wait_chunk_to(l4shmc_chunk_t *p, l4_timeout_t to)
377 return l4shmc_wait_signal_to(p->_sig, to);