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>
20 #include <l4/util/util.h>
21 #include <l4/util/atomic.h>
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)
30 l4_umword_t lock; // lock for handling chunks
31 l4_addr_t _first_chunk; // offset to first chunk
35 SHMAREA_LOCK_FREE, SHMAREA_LOCK_TAKEN,
39 static inline l4shmc_chunk_desc_t *
40 chunk_get(l4_addr_t o, void *shm_local_addr)
42 return (l4shmc_chunk_desc_t *)(o + (l4_addr_t)shm_local_addr);
46 l4shmc_create(const char *shm_name, l4_umword_t shm_size)
49 l4re_ds_t shm_ds = L4_INVALID_CAP;
50 l4re_namespace_t tmp = L4_INVALID_CAP;
53 if (l4_is_invalid_cap(shm_ds = l4re_util_cap_alloc()))
56 if ((r = l4re_ma_alloc(shm_size, shm_ds, 0)))
59 if ((r = l4re_rm_attach((void **)&s, shm_size, L4RE_RM_SEARCH_ADDR, shm_ds,
66 if (l4_is_invalid_cap(tmp = l4re_util_cap_alloc()))
69 tmp = l4re_get_env_cap(shm_name);
70 if (l4_is_invalid_cap(tmp))
76 if ((r = l4re_ns_register_obj_srv(tmp, "shm", shm_ds, L4RE_NS_REGISTER_RW)))
79 l4re_rm_detach_unmap((l4_addr_t)s, L4RE_THIS_TASK_CAP);
84 if (!l4_is_invalid_cap(tmp))
85 l4re_util_cap_free(tmp);
91 l4shmc_attach_to(const char *shm_name, l4_umword_t timeout_ms,
92 l4shmc_area_t *shmarea)
95 l4re_namespace_t nssrv;
97 strncpy(shmarea->_name, shm_name, sizeof(shmarea->_name));
98 shmarea->_name[sizeof(shmarea->_name) - 1] = 0;
100 if (l4_is_invalid_cap(shmarea->_shm_ds = l4re_util_cap_alloc()))
103 nssrv = l4re_get_env_cap(shm_name);
104 if (l4_is_invalid_cap(nssrv))
106 printf("shm: did not find '%s' namespace\n", shm_name);
110 if (l4re_ns_query_to_srv(nssrv, "shm", shmarea->_shm_ds, timeout_ms))
112 printf("shm: did not find shm-ds 'shm'\n");
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,
128 l4shmc_add_chunk(l4shmc_area_t *shmarea,
129 const char *chunk_name,
130 l4_umword_t chunk_capacity,
131 l4shmc_chunk_t *chunk)
133 shared_mem_t *shm_addr = (shared_mem_t *)shmarea->_local_addr;
135 l4shmc_chunk_desc_t *p;
136 l4shmc_chunk_desc_t *prev = NULL;
140 while (!l4util_cmpxchg(&shm_addr->lock, SHMAREA_LOCK_FREE,
143 asm volatile ("" : : : "memory");
147 if (shm_addr->_first_chunk)
149 offs = shm_addr->_first_chunk;
150 p = chunk_get(offs, shmarea->_local_addr);
153 offs = p->_offset + p->_capacity + sizeof(*p);
155 p = chunk_get(p->_next, shmarea->_local_addr);
160 // first chunk starts right after shm-header
161 offs = sizeof(shared_mem_t);
163 if ((shm_sz = l4shmc_area_size(shmarea)) < 0)
166 if (offs + chunk_capacity + sizeof(*p) >= (unsigned long)shm_sz)
167 return -L4_ENOMEM; // no more free memory in this shm
169 p = chunk_get(offs, shmarea->_local_addr);
172 p->_capacity = chunk_capacity;
177 shm_addr->_first_chunk = offs;
179 asm volatile ("" : : : "memory");
180 shm_addr->lock = SHMAREA_LOCK_FREE;
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;
189 chunk->_shm = shmarea;
196 l4shmc_add_signal(l4shmc_area_t *shmarea,
197 const char *signal_name,
198 l4shmc_signal_t *signal)
200 /* Now that the chunk is allocated in the shm, lets get the UIRQ
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))
209 if ((r = l4_error(l4_factory_create_irq(l4re_env()->factory,
213 snprintf(b, sizeof(b) - 1, "sig-%s", signal_name);
214 b[sizeof(b) - 1] = 0;
216 tmp = l4re_get_env_cap(shmarea->_name);
217 if (l4_is_invalid_cap(tmp))
220 if (l4re_ns_register_obj_srv(tmp, b, signal->_sigcap, 0))
222 l4re_util_cap_free(tmp);
226 l4re_util_cap_free(tmp);
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)
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;
242 l4_addr_t offs = shm_addr->_first_chunk;
245 l4shmc_chunk_desc_t *p;
246 p = chunk_get(offs, shmarea->_local_addr);
248 if (!strcmp(p->_name, chunk_name))
250 chunk->_shm = shmarea;
261 l4_sleep(100); // sleep 100ms
263 while (l4re_kip()->clock < try_until);
269 l4shmc_attach_signal_to(l4shmc_area_t *shmarea,
270 const char *signal_name,
272 l4_umword_t timeout_ms,
273 l4shmc_signal_t *signal)
277 r = l4shmc_get_signal_to(shmarea, signal_name, timeout_ms, signal);
281 if ((r = l4_error(l4_irq_attach(signal->_sigcap,
282 (l4_umword_t)signal, thread))))
284 l4re_util_cap_free(signal->_sigcap);
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)
298 char b[L4SHMC_NAME_STRINGLEN + L4SHMC_SIGNAL_NAME_SIZE + 5]; // strings + "sig-"
301 signal->_sigcap = l4re_util_cap_alloc();
303 if (l4_is_invalid_cap(signal->_sigcap))
306 ns = l4re_get_env_cap(shmarea->_name);
307 if (l4_is_invalid_cap(ns))
310 snprintf(b, sizeof(b) - 1, "sig-%s", signal_name);
311 b[sizeof(b) - 1] = 0;
313 if (l4re_ns_query_to_srv(ns, b, signal->_sigcap, timeout_ms))
322 l4shmc_connect_chunk_signal(l4shmc_chunk_t *chunk,
323 l4shmc_signal_t *signal)
325 chunk->_sig = signal;
330 l4shmc_enable_signal(l4shmc_signal_t *s)
332 return l4_error(l4_irq_unmask(s->_sigcap));
336 l4shmc_enable_chunk(l4shmc_chunk_t *p)
338 return l4shmc_enable_signal(p->_sig);
342 l4shmc_wait_any_to(l4_timeout_t timeout, l4shmc_signal_t **p)
347 if ((r = l4_ipc_error(l4_ipc_wait(l4_utcb(), &l, timeout), l4_utcb())))
350 *p = (l4shmc_signal_t *)l;
356 l4shmc_wait_signal_to(l4shmc_signal_t *s, l4_timeout_t timeout)
360 if ((r = l4_ipc_error(l4_irq_receive(s->_sigcap, timeout), l4_utcb())))
367 l4shmc_wait_chunk_to(l4shmc_chunk_t *p, l4_timeout_t to)
369 return l4shmc_wait_signal_to(p->_sig, to);