aboutsummaryrefslogtreecommitdiffstats
path: root/src/lua/lua_thread_pool.c
blob: 6effbe76931cd827f633a02bbde1a513320acadd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#include "config.h"

#include <assert.h>

#include "lua_common.h"
#include "lua_thread_pool.h"

struct lua_thread_pool {
	GQueue *available_items;
	lua_State *L;
	gint max_items;
	struct thread_entry *running_entry;
};

static struct thread_entry *
thread_entry_new (lua_State * L)
{
	struct thread_entry *ent;
	ent = g_malloc (sizeof *ent);
	ent->lua_state = lua_newthread (L);
	ent->thread_index = luaL_ref (L, LUA_REGISTRYINDEX);
	return ent;
}

static void
thread_entry_free (lua_State * L, struct thread_entry *ent)
{
	luaL_unref (L, LUA_REGISTRYINDEX, ent->thread_index);
	g_free (ent);
}

struct lua_thread_pool *
lua_thread_pool_new (lua_State * L)
{
	struct lua_thread_pool * pool = g_new0 (struct lua_thread_pool, 1);

	pool->L = L;
	pool->max_items = 100;

	pool->available_items = g_queue_new ();
	int i;

	struct thread_entry *ent;
	for (i = 0; i < pool->max_items; i ++) {
		ent = thread_entry_new (pool->L);
		g_queue_push_head (pool->available_items, ent);
	}

	return pool;
}

void
lua_thread_pool_free (struct lua_thread_pool *pool)
{
	struct thread_entry *ent = NULL;
	while (!g_queue_is_empty (pool->available_items)) {
		ent = g_queue_pop_head (pool->available_items);
		thread_entry_free (pool->L, ent);
	}
	g_queue_free (pool->available_items);
	g_free (pool);
}

struct thread_entry *
lua_thread_pool_get(struct lua_thread_pool *pool)
{
	gpointer cur;
	struct thread_entry *ent = NULL;

	cur = g_queue_pop_head (pool->available_items);

	if (cur) {
		ent = cur;
	}
	else {
		ent = thread_entry_new (pool->L);
	}
	return ent;
}

void
lua_thread_pool_return(struct lua_thread_pool *pool, struct thread_entry *thread_entry)
{
	assert (lua_status (thread_entry->lua_state) == 0); // we can't return a running/yielded stack into the pool
	if (pool->running_entry == thread_entry) {
		pool->running_entry = NULL;
	}
	if (g_queue_get_length (pool->available_items) <= pool->max_items) {
		g_queue_push_head (pool->available_items, thread_entry);
	}
	else {
		thread_entry_free (pool->L, thread_entry);
	}
}

void
lua_thread_pool_terminate_entry(struct lua_thread_pool *pool, struct thread_entry *thread_entry)
{
	struct thread_entry *ent = NULL;

	if (pool->running_entry == thread_entry) {
		pool->running_entry = NULL;
	}

	// we should only terminate failed threads
	assert (lua_status (thread_entry->lua_state) != 0 && lua_status (thread_entry->lua_state) != LUA_YIELD);
	thread_entry_free (pool->L, thread_entry);

	if (g_queue_get_length (pool->available_items) <= pool->max_items) {
		ent = thread_entry_new (pool->L);
		g_queue_push_head (pool->available_items, ent);
	}
}

struct thread_entry *
lua_thread_pool_get_running_entry(struct lua_thread_pool *pool)
{
	return pool->running_entry;
}

void
lua_thread_pool_set_running_entry(struct lua_thread_pool *pool, struct thread_entry *thread_entry)
{
	pool->running_entry = thread_entry;
}