blob: dfc0c988d86426d58b5e394c953290d78d020be2 [file]
/*
* Copyright 2018, Data61, CSIRO (ABN 41 687 119 230)
*
* SPDX-License-Identifier: BSD-2-Clause
*/
// #define ZF_LOG_LEVEL ZF_LOG_DEBUG
#include <utils/util.h>
#include <sync/mutex.h>
#include <camkes/sync.h>
#include <camkes/allocator.h>
#include <camkes/tls.h>
/* Allocates a mutex using camkes_alloc */
static void *camkes_mutex_new(void)
{
ZF_LOGD("called by %p",
camkes_get_tls()->thread_index);
/* The arguments to camkes_alloc need to match what arguements were given when the objects were added
* to the allocator by the camkes runtime. It treates notification objects as 0 sized and with Read
* Write cap rights. */
seL4_CPtr cap = camkes_alloc(seL4_NotificationObject, 0, seL4_CanRead.words[0] | seL4_CanWrite.words[0]);
if (cap == seL4_CapNull) {
ZF_LOGE("Failed to allocate notification object");
return NULL;
}
/* Allocate underlying mutex struct. We use the implementation from libsel4sync */
sync_mutex_t *mtx = calloc(1, sizeof(mtx[0]));
if (mtx == NULL) {
ZF_LOGE("ENOMEM allocating malloc");
camkes_free(cap);
return NULL;
}
/* Init the mutex. */
int res = sync_mutex_init(mtx, cap);
if (res) {
ZF_LOGE("sync_mutex_init failed");
free(mtx);
camkes_free(cap);
return NULL;
}
return mtx;
}
static int camkes_mutex_lock(void *mutex)
{
ZF_LOGD("called by %p on cap %d",
camkes_get_tls()->thread_index,
((sync_mutex_t *)mutex)->notification.cptr);
return sync_mutex_lock(mutex);
}
static int camkes_mutex_unlock(void *mutex)
{
ZF_LOGD("called by %p on cap %d",
camkes_get_tls()->thread_index,
((sync_mutex_t *)mutex)->notification.cptr);
return sync_mutex_unlock(mutex);
}
/* Free a mutex back to the camkes allocator */
static int camkes_mutex_free(void *mutex)
{
ZF_LOGD("called by %p on cap %d",
camkes_get_tls()->thread_index,
((sync_mutex_t *)mutex)->notification.cptr);
/* There isn't a sync_mutex_free for a preallocated mutex.
* We just release the Cap the notification object to the camkes allocator.
*/
sync_mutex_t *mtx = mutex;
camkes_free(mtx->notification.cptr);
free(mtx);
return 0;
}
/**
* Populates function pointers. Takes a preallocated struct.
*/
int init_camkes_mutex_ops(ps_mutex_ops_t *mutex_ops)
{
if (mutex_ops == NULL) {
ZF_LOGE("Trying to init a NULL mutex_ops");
return -1;
}
ps_mutex_ops_t mutex_ops_interface = {
.mutex_new = camkes_mutex_new,
.mutex_lock = camkes_mutex_lock,
.mutex_unlock = camkes_mutex_unlock,
.mutex_destroy = camkes_mutex_free,
};
*mutex_ops = mutex_ops_interface;
return 0;
}
/**
* Allocates the allocator struct and then calls init_default_allocator
*/
int init_camkes_mutex_ops_heap(ps_mutex_ops_t **mutex_ops)
{
if (mutex_ops == NULL) {
ZF_LOGE("Trying to init a NULL mutex_ops");
return -1;
}
*mutex_ops = malloc(sizeof(ps_mutex_ops_t));
if (*mutex_ops == NULL) {
ZF_LOGE("Trying to init a NULL allocator");
return -1;
}
return init_camkes_mutex_ops(*mutex_ops);
}