#include <linux/time.h>
#include <linux/completion.h>
#include <linux/version.h>
+#include <linux/hashtable.h>
#include <uapi/linux/vlogger.h>
#define MB (1 << 20)
#define V_BLOCK_SIZE (2 * KB)
#define BLOCK_COUNT (BUFFER_SIZE / V_BLOCK_SIZE)
#define DATA_MAX (V_BLOCK_SIZE - sizeof(struct head_t))
-// TODO: We do not want to have a MAX_THREAD limitation. Remove this.
-#define MAX_THREAD (0x8000)
#define MS_PER_SEC (1000)
#define NS_PER_SEC (1000000000UL)
uint16_t *values;
};
+struct thread_table_field {
+ pid_t tid;
+ uint16_t blk;
+ struct hlist_node next;
+};
+
+struct thread_table {
+ DECLARE_HASHTABLE(data, 16);
+};
+
// taken from dlog.h
typedef enum {
DLOG_UNKNOWN = 0, /**< Keep this always at the start */
static int g_init;
static char *g_shm_ptr[DEVICE_COUNT];
-// TODO: Having an array indexed by TIDs is unnacceptable.
-static struct thread_t *g_threads;
+static struct thread_table *g_thread_table;
-// TODO: g_block_mutex is basically smoke and mirrors,
-// since the protected array is basically world-writable
-// and can change at any time.
static struct mutex g_block_mutex;
static struct mutex g_task_mutex;
}
#endif
+static uint16_t get_thread_table(pid_t tid)
+{
+ struct thread_table_field *ptr = NULL;
+
+ // TODO: Is this needed?
+ if (g_thread_table == NULL)
+ return 0;
+
+ hash_for_each_possible(g_thread_table->data, ptr, next, tid) {
+ if (ptr->tid == tid) {
+ return ptr->blk;
+ }
+ }
+
+ return 0;
+}
+
+static void set_thread_table(pid_t tid, uint16_t blk)
+{
+ struct thread_table_field *ptr = NULL;
+
+ // TODO: Is this needed?
+ if (g_thread_table == NULL)
+ return;
+
+ hash_for_each_possible(g_thread_table->data, ptr, next, tid) {
+ if (ptr->tid == tid) {
+ ptr->blk = blk;
+ return;
+ }
+ }
+
+ ptr = kzalloc(sizeof(*ptr), GFP_KERNEL);
+ ptr->tid = tid;
+ ptr->blk = blk;
+ hash_add(g_thread_table->data, &ptr->next, tid);
+}
+
static inline char *get_shared_memory(int dev_index)
{
if (dev_index < 0 || dev_index >= DEVICE_COUNT) {
uint16_t blk;
do {
+ // TODO: Consider hash_for_each_safe
for (i = 1; i <= g_max_thread_id; i++) {
- blk = g_threads[i].block;
+ blk = get_thread_table(i);
// TODO: g_start_time should be under some kind of mutex.
if (blk && get_block(blk)->head.ts < g_start_time) {
mutex_lock(&g_block_mutex);
get_block(blk)->head.tid = 0;
queue_push(&g_free_q, blk);
- g_threads[i].block = 0;
+ set_thread_table(i, 0);
// TODO: The userspace might very well be using this block right now.
mutex_unlock(&g_block_mutex);
g_free_count++;
uint16_t blk;
struct block_t *block;
- if (tid >= MAX_THREAD) {
- pr_err("Invalid tid: %d", tid);
- return -EINVAL;
- }
-
if (g_max_thread_id < tid)
g_max_thread_id = tid;
mutex_lock(&g_block_mutex);
- blk = g_threads[tid].block;
+ blk = get_thread_table(tid);
if (blk)
queue_push(&g_free_q, blk);
blk = queue_pop(&g_free_q);
- g_threads[tid].block = blk;
+ set_thread_table(tid, blk);
if (!blk) {
if ((g_err_count++ % 10000) < 3)
uint16_t blk = 0;
long r;
- if (g_threads == NULL)
- return NULL;
-
- blk = g_threads[tid].block;
+ blk = get_thread_table(tid);
if (blk != 0) {
struct block_t *block = get_block(blk);
static ssize_t status_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- int thread_count = 0;
- int i;
-
- for (i = 0; i < MAX_THREAD; i++) {
- if (g_threads[i].block > 0)
- thread_count ++;
- }
-
- return snprintf(buf, PAGE_SIZE,
- "free(%d%%):%d/%d task_on:%d gc_free:%u error:%u tid_max:%d\n",
- BLOCK_RATIO(g_free_q.count), g_free_q.count, (g_free_q.count + thread_count),
- g_task_on, g_free_count, g_err_count, g_max_thread_id);
+ // int thread_count = 0;
+ // int i;
+
+ // for (i = 0; i < MAX_THREAD; i++) {
+ // if (g_threads[i].block > 0)
+ // thread_count ++;
+ // }
+
+ // return snprintf(buf, PAGE_SIZE,
+ // "free(%d%%):%d/%d task_on:%d gc_free:%u error:%u tid_max:%d\n",
+ // BLOCK_RATIO(g_free_q.count), g_free_q.count, (g_free_q.count + thread_count),
+ // g_task_on, g_free_count, g_err_count, g_max_thread_id);
+ return -ENOTSUPP; // TODO
}
static DEVICE_ATTR_RO(status);
static ssize_t thread_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- return snprintf(buf, PAGE_SIZE, "[%d] block:%u\n", g_thread, g_threads[g_thread].block);
+ // return snprintf(buf, PAGE_SIZE, "[%d] block:%u\n", g_thread, g_threads[g_thread].block);
+ return -ENOTSUPP; // TODO
}
static DEVICE_ATTR_RW(thread);
return r;
}
- g_threads = kzalloc(sizeof(struct thread_t) * MAX_THREAD, GFP_KERNEL);
- if (g_threads == NULL)
+ g_thread_table = kzalloc(sizeof(struct thread_table), GFP_KERNEL);
+ if (g_thread_table == NULL)
return -ENOMEM;
+ hash_init(g_thread_table->data);
for (g_shm_ptr_i = 0; g_shm_ptr_i < DEVICE_COUNT; g_shm_ptr_i++) {
g_shm_ptr[g_shm_ptr_i] = kzalloc(MAP_SIZE, GFP_KERNEL);
if (g_shm_ptr[g_shm_ptr_i] == NULL) {
r = -ENOMEM;
- goto out_free_g_threads_g_shm_ptr;
+ goto out_free_g_thread_table_g_shm_ptr;
}
}
return 0;
-out_free_g_threads_g_shm_ptr:
+out_free_g_thread_table_g_shm_ptr:
for (i = 0; i < g_shm_ptr_i; ++i)
kfree(g_shm_ptr[i]);
- kfree(g_threads);
+ kfree(g_thread_table);
return r;
}
// TODO: What about the task that is running in the background?
queue_deinit(&g_free_q);
- kfree(g_threads);
+ kfree(g_thread_table); // TODO: Free innards
for (i = 0; i < DEVICE_COUNT; i++)
kfree(g_shm_ptr[i]);