You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
82 lines
1.7 KiB
82 lines
1.7 KiB
#pragma once
|
|
|
|
#include <assert.h>
|
|
#include <spinlock/mcs.h>
|
|
#include <stdint.h>
|
|
|
|
#include "arch/getcycles.h"
|
|
#include "runtime.h"
|
|
|
|
|
|
/* A linked list of nodes */
|
|
struct lock_wrapper {
|
|
uint64_t longest_held;
|
|
uint64_t total_held;
|
|
ck_spinlock_mcs_t lock;
|
|
};
|
|
|
|
/* A node on the linked list */
|
|
struct lock_node {
|
|
struct ck_spinlock_mcs node;
|
|
uint64_t time_locked;
|
|
};
|
|
|
|
typedef struct lock_wrapper lock_t;
|
|
typedef struct lock_node lock_node_t;
|
|
|
|
/**
|
|
* Initializes a lock
|
|
* @param lock - the address of the lock
|
|
*/
|
|
static inline void
|
|
lock_init(lock_t *self)
|
|
{
|
|
self->total_held = 0;
|
|
self->longest_held = 0;
|
|
ck_spinlock_mcs_init(&self->lock);
|
|
}
|
|
|
|
/**
|
|
* Checks if a lock is locked
|
|
* @param lock - the address of the lock
|
|
* @returns bool if lock is locked
|
|
*/
|
|
static inline bool
|
|
lock_is_locked(lock_t *self)
|
|
{
|
|
return ck_spinlock_mcs_locked(&self->lock);
|
|
}
|
|
|
|
/**
|
|
* Locks a lock, keeping track of overhead
|
|
* @param lock - the address of the lock
|
|
* @param node - node to add to lock
|
|
*/
|
|
static inline void
|
|
lock_lock(lock_t *self, lock_node_t *node)
|
|
{
|
|
assert(node->time_locked == 0);
|
|
|
|
node->time_locked = __getcycles();
|
|
ck_spinlock_mcs_lock(&self->lock, &node->node);
|
|
}
|
|
|
|
/**
|
|
* Unlocks a lock
|
|
* @param lock - the address of the lock
|
|
* @param node - node used when calling lock_lock
|
|
*/
|
|
static inline void
|
|
lock_unlock(lock_t *self, lock_node_t *node)
|
|
{
|
|
assert(node->time_locked > 0);
|
|
|
|
ck_spinlock_mcs_unlock(&self->lock, &node->node);
|
|
uint64_t now = __getcycles();
|
|
assert(node->time_locked < now);
|
|
uint64_t duration = now - node->time_locked;
|
|
node->time_locked = 0;
|
|
if (unlikely(duration > self->longest_held)) { self->longest_held = duration; }
|
|
self->total_held += duration;
|
|
}
|