SHMAREA_LOCK_FREE, SHMAREA_LOCK_TAKEN,
};
+enum {
+ MAX_SIZE = (~0UL) >> 1,
+};
static inline l4shmc_chunk_desc_t *
chunk_get(l4_addr_t o, void *shm_local_addr)
shared_mem_t *s;
l4re_ds_t shm_ds = L4_INVALID_CAP;
l4re_namespace_t shm_cap;
- long r = -L4_ENOMEM;
+ long r;
- shm_cap = l4re_get_env_cap(shm_name);
+ if (shm_size > MAX_SIZE)
+ return -L4_ENOMEM;
+
+ shm_cap = l4re_env_get_cap(shm_name);
if (l4_is_invalid_cap(shm_cap))
return -L4_ENOENT;
goto out_shm_free_mem;
s->_first_chunk = 0;
+ s->lock = SHMAREA_LOCK_FREE;
- r = L4_EOK;
if ((r = l4re_ns_register_obj_srv(shm_cap, "shm", shm_ds, L4RE_NS_REGISTER_RW)))
- r = -L4_EINVAL;
+ goto out_shm_free_mem;
l4re_rm_detach_unmap((l4_addr_t)s, L4RE_THIS_TASK_CAP);
- return r;
+ return 0;
out_shm_free_mem:
l4re_ma_free(shm_ds);
l4shmc_attach_to(const char *shm_name, l4_umword_t timeout_ms,
l4shmc_area_t *shmarea)
{
- long r;
+ long r = -L4_ENOENT;
l4re_namespace_t nssrv;
strncpy(shmarea->_name, shm_name, sizeof(shmarea->_name));
shmarea->_name[sizeof(shmarea->_name) - 1] = 0;
+ shmarea->_local_addr = 0;
if (l4_is_invalid_cap(shmarea->_shm_ds = l4re_util_cap_alloc()))
return -L4_ENOMEM;
- nssrv = l4re_get_env_cap(shm_name);
+ nssrv = l4re_env_get_cap(shm_name);
if (l4_is_invalid_cap(nssrv))
{
printf("shm: did not find '%s' namespace\n", shm_name);
- return -L4_ENOENT;
+ goto out_free_cap;
}
if ((r = l4re_ns_query_to_srv(nssrv, "shm", shmarea->_shm_ds, timeout_ms)))
{
printf("shm: did not find shm-ds 'shm' (%ld)\n", r);
- return -L4_ENOENT;
+ goto out_free_cap;
}
- shmarea->_local_addr = 0;
- if ((r = l4re_rm_attach(&shmarea->_local_addr,
- l4shmc_area_size(shmarea),
+ r = l4shmc_area_size(shmarea);
+ if (r < 0)
+ {
+ r = -L4_ENOMEM;
+ goto out_free_cap;
+ }
+ shmarea->_size = r;
+
+ if ((r = l4re_rm_attach(&shmarea->_local_addr, shmarea->_size,
L4RE_RM_SEARCH_ADDR, shmarea->_shm_ds,
0, L4_PAGESHIFT)))
- return r;
+ goto out_free_cap;
return L4_EOK;
+
+out_free_cap:
+ l4re_util_cap_free(shmarea->_shm_ds);
+ return r;
}
+L4_CV long
+l4shmc_area_overhead(void)
+{
+ return sizeof(shared_mem_t);
+}
+
+L4_CV long
+l4shmc_chunk_overhead(void)
+{
+ return sizeof(l4shmc_chunk_desc_t);
+}
+
+static long next_chunk(l4shmc_area_t *shmarea, l4_addr_t offs)
+{
+ shared_mem_t *shm_addr = (shared_mem_t *)shmarea->_local_addr;
+ volatile l4shmc_chunk_desc_t *p;
+ l4_addr_t next;
+
+ if (offs == 0)
+ {
+ next = shm_addr->_first_chunk;
+ }
+ else
+ {
+ p = chunk_get(offs, shmarea->_local_addr);
+ next = p->_next;
+ }
+ if (next == 0)
+ return 0;
+ if (next >= shmarea->_size || next + sizeof(*p) >= shmarea->_size || next <= offs)
+ return -L4_EIO;
+ if (next % sizeof(l4_addr_t) != 0)
+ return -L4_EINVAL;
+ p = chunk_get(next, shmarea->_local_addr);
+ if (p->_magic != L4SHMC_CHUNK_MAGIC)
+ return -L4_EIO;
+ return next;
+}
+
+L4_CV long
+l4shmc_iterate_chunk(l4shmc_area_t *shmarea, const char **chunk_name, long offs)
+{
+ if (offs < 0)
+ return -L4_EINVAL;
+ offs = next_chunk(shmarea, offs);
+ if (offs > 0)
+ {
+ l4shmc_chunk_desc_t *p = chunk_get(offs, shmarea->_local_addr);
+ *chunk_name = p->_name;
+ }
+ return offs;
+}
L4_CV long
l4shmc_add_chunk(l4shmc_area_t *shmarea,
{
shared_mem_t *shm_addr = (shared_mem_t *)shmarea->_local_addr;
- l4shmc_chunk_desc_t *p;
+ l4shmc_chunk_desc_t *p = NULL;
l4shmc_chunk_desc_t *prev = NULL;
+ l4_addr_t offs = 0;
+ long ret;
- shm_addr->lock = 0;
+ if (chunk_capacity >> (sizeof(chunk_capacity) * 8 - 1))
+ return -L4_ENOMEM;
while (!l4util_cmpxchg(&shm_addr->lock, SHMAREA_LOCK_FREE,
SHMAREA_LOCK_TAKEN))
l4_sleep(1);
asm volatile ("" : : : "memory");
- {
- l4_addr_t offs;
- long shm_sz;
- if (shm_addr->_first_chunk)
- {
- offs = shm_addr->_first_chunk;
- p = chunk_get(offs, shmarea->_local_addr);
- do
- {
- offs = p->_offset + p->_capacity + sizeof(*p);
- prev = p;
- p = chunk_get(p->_next, shmarea->_local_addr);
- }
- while (prev->_next);
- }
- else
- // first chunk starts right after shm-header
- offs = sizeof(shared_mem_t);
-
- if ((shm_sz = l4shmc_area_size(shmarea)) < 0)
- return -L4_ENOMEM;
-
- if (offs + chunk_capacity + sizeof(*p) >= (unsigned long)shm_sz)
- return -L4_ENOMEM; // no more free memory in this shm
-
- p = chunk_get(offs, shmarea->_local_addr);
- p->_offset = offs;
- p->_next = 0;
- p->_capacity = chunk_capacity;
-
- if (prev)
- prev->_next = offs;
- else
- shm_addr->_first_chunk = offs;
- }
- asm volatile ("" : : : "memory");
- shm_addr->lock = SHMAREA_LOCK_FREE;
+ while ((ret = next_chunk(shmarea, offs)) > 0)
+ {
+ p = chunk_get(ret, shmarea->_local_addr);
+ if (strcmp(p->_name, chunk_name) == 0)
+ {
+ ret = -L4_EEXIST;
+ goto out_free_lock;
+ }
+ offs = ret;
+ }
+ if (ret < 0)
+ goto out_free_lock;
+ if (offs == 0)
+ offs = sizeof(shared_mem_t);
+ else
+ {
+ l4_addr_t n = p->_offset + p->_capacity + sizeof(*p);
+ if (n <= offs || n >= shmarea->_size)
+ {
+ ret = -L4_EIO;
+ goto out_free_lock;
+ }
+ offs = n;
+ prev = p;
+ }
- p->_size = 0;
+ if (offs + chunk_capacity + sizeof(*p) > (unsigned long)shmarea->_size)
+ {
+ ret = -L4_ENOMEM;
+ goto out_free_lock; // no more free memory in this shm
+ }
+ p = chunk_get(offs, shmarea->_local_addr);
+ p->_offset = offs;
+ p->_next = 0;
+ p->_capacity = chunk_capacity;
+ p->_size = 0;
p->_status = L4SHMC_CHUNK_CLEAR;
- p->_magic = L4SHMC_CHUNK_MAGIC;
+ p->_magic = L4SHMC_CHUNK_MAGIC;
strncpy(p->_name, chunk_name, sizeof(p->_name));
p->_name[sizeof(p->_name) - 1] = 0;
+ // Ensure that other CPUs have correct data before inserting chunk
+ __sync_synchronize();
+
+ if (prev)
+ prev->_next = offs;
+ else
+ shm_addr->_first_chunk = offs;
+
+ __sync_synchronize();
+ shm_addr->lock = SHMAREA_LOCK_FREE;
- chunk->_chunk = p;
- chunk->_shm = shmarea;
- chunk->_sig = NULL;
+ chunk->_chunk = p;
+ chunk->_shm = shmarea;
+ chunk->_sig = NULL;
+ chunk->_capacity = chunk_capacity;
return L4_EOK;
+out_free_lock:
+ shm_addr->lock = SHMAREA_LOCK_FREE;
+ return ret;
+}
+
+L4_CV long
+l4shmc_area_size_free(l4shmc_area_t *shmarea)
+{
+ long ret;
+ l4_addr_t offs = 0;
+ while ((ret = next_chunk(shmarea, offs)) > 0)
+ offs = ret;
+ if (ret < 0)
+ return ret;
+ ret = shmarea->_size - offs;
+ return ret > 0 ? ret : 0;
}
L4_CV long
long r;
l4re_namespace_t tmp;
char b[L4SHMC_NAME_STRINGLEN + L4SHMC_SIGNAL_NAME_SIZE + 5]; // strings + "sig-"
+
+ tmp = l4re_env_get_cap(shmarea->_name);
+ if (l4_is_invalid_cap(tmp))
+ return -L4_ENOENT;
+
signal->_sigcap = l4re_util_cap_alloc();
if (l4_is_invalid_cap(signal->_sigcap))
return -L4_ENOMEM;
if ((r = l4_error(l4_factory_create_irq(l4re_env()->factory,
signal->_sigcap))))
- return r;
+ goto out_free_cap;
snprintf(b, sizeof(b) - 1, "sig-%s", signal_name);
b[sizeof(b) - 1] = 0;
- tmp = l4re_get_env_cap(shmarea->_name);
- if (l4_is_invalid_cap(tmp))
- return -L4_ENOENT;
-
- if (l4re_ns_register_obj_srv(tmp, b, signal->_sigcap, 0))
- {
- l4re_util_cap_free(tmp);
- return -L4_ENOENT;
- }
-
- l4re_util_cap_free(tmp);
+ r = l4re_ns_register_obj_srv(tmp, b, signal->_sigcap, 0);
+ if (r)
+ goto out_unmap_irq;
return L4_EOK;
+
+out_unmap_irq:
+ l4_task_unmap(L4_BASE_TASK_CAP,
+ l4_obj_fpage(signal->_sigcap, 0, L4_FPAGE_RWX),
+ L4_FP_ALL_SPACES);
+out_free_cap:
+ l4re_util_cap_free(signal->_sigcap);
+ return r;
}
L4_CV long
l4shmc_chunk_t *chunk)
{
l4_kernel_clock_t try_until = l4re_kip()->clock + (timeout_ms * 1000);
- shared_mem_t *shm_addr = (shared_mem_t *)shmarea->_local_addr;
+ long ret;
do
{
- l4_addr_t offs = shm_addr->_first_chunk;
- while (offs)
+ l4_addr_t offs = 0;
+ while ((ret = next_chunk(shmarea, offs)) > 0)
{
l4shmc_chunk_desc_t *p;
+ offs = ret;
p = chunk_get(offs, shmarea->_local_addr);
-
if (!strcmp(p->_name, chunk_name))
{ // found it!
- chunk->_shm = shmarea;
- chunk->_chunk = p;
- chunk->_sig = NULL;
+ chunk->_shm = shmarea;
+ chunk->_chunk = p;
+ chunk->_sig = NULL;
+ chunk->_capacity = p->_capacity;
+ if (chunk->_capacity > shmarea->_size ||
+ chunk->_capacity + offs > shmarea->_size)
+ return -L4_EIO;
return L4_EOK;
}
- offs = p->_next;
}
+ if (ret < 0)
+ return ret;
if (!timeout_ms)
break;
- l4_sleep(100); // sleep 100ms
+ l4_sleep(100);
}
while (l4re_kip()->clock < try_until);
l4re_namespace_t ns;
l4_cpu_time_t timeout;
- signal->_sigcap = l4re_util_cap_alloc();
+ ns = l4re_env_get_cap(shmarea->_name);
+ if (l4_is_invalid_cap(ns))
+ return -L4_ENOENT;
+ signal->_sigcap = l4re_util_cap_alloc();
if (l4_is_invalid_cap(signal->_sigcap))
return -L4_ENOMEM;
- ns = l4re_get_env_cap(shmarea->_name);
- if (l4_is_invalid_cap(ns))
- return -L4_ENOENT;
-
snprintf(b, sizeof(b) - 1, "sig-%s", signal_name);
b[sizeof(b) - 1] = 0;
{
int e = l4re_ns_query_to_srv(ns, b, signal->_sigcap, timeout_ms);
if (e != -L4_ENOENT)
- return e;
+ {
+ if (e)
+ l4re_util_cap_free(signal->_sigcap);
+ return e;
+ }
if (l4re_kip()->clock < timeout)
l4_sleep(100);
else
break;
}
- return L4_EOK;
+ return -L4_ENOENT;
}