]> jfr.im git - irc/quakenet/newserv.git/blob - lua/luascheduler.c
LUA: port luadb to dbapi2 to drop postgres dependency
[irc/quakenet/newserv.git] / lua / luascheduler.c
1 #include "../core/schedule.h"
2 #include "../core/error.h"
3 #include "lua.h"
4
5 #define SCHEDULER_METATABLE "newserv.scheduler"
6 #define SCHEDULER_ENTRY_METATABLE "newserv.schedulerentry"
7
8 static int lua_scheduler_new(lua_State *ps) {
9 lua_scheduler *result;
10 lua_list *ll = lua_listfromstate(ps);
11 if(!ll)
12 return 0;
13
14 result = (lua_scheduler *)lua_newuserdata(ps, sizeof(lua_scheduler));
15 if(!result)
16 return 0;
17
18 luaL_getmetatable(ps, SCHEDULER_METATABLE);
19 lua_setmetatable(ps, -2);
20
21 result->count = 0;
22 result->entries = NULL;
23 result->ps = ps;
24 result->next = ll->schedulers;
25 ll->schedulers = result;
26
27 return 1;
28 }
29
30 static void remove_entry(lua_scheduler_entry *entry) {
31 if(entry->prev) {
32 entry->prev->next = entry->next;
33 } else {
34 entry->sched->entries = entry->next;
35 }
36
37 if(entry->next) {
38 entry->next->prev = entry->prev;
39 } else {
40 /* no tail pointer! */
41 }
42
43 entry->next = NULL;
44 entry->prev = NULL;
45 entry->psch = NULL;
46 }
47
48 static void free_entry(lua_scheduler_entry *entry) {
49 luaL_unref(entry->sched->ps, LUA_REGISTRYINDEX, entry->ref);
50 free(entry);
51 }
52
53 static int valid_entry(lua_scheduler_entry *entry) {
54 if(!entry || !entry->psch) {
55 Error("lua", ERR_WARNING, "Invalid scheduler entry: %p", entry);
56 return 0;
57 }
58
59 return 1;
60 }
61
62 static void scheduler_exec(void *arg) {
63 lua_scheduler_entry *entry = (lua_scheduler_entry *)arg;
64
65 if(!valid_entry(entry))
66 return;
67
68 remove_entry(entry);
69
70 _lua_vpcall(entry->sched->ps, (void *)(long)entry->ref, LUA_POINTERMODE, "");
71
72 free_entry(entry);
73 }
74
75 static lua_scheduler *lua_toscheduler(lua_State *ps, int arg) {
76 void *ud = luaL_checkudata(ps, 1, SCHEDULER_METATABLE);
77 if(!ud)
78 return NULL;
79
80 return (lua_scheduler *)ud;
81 }
82
83 static int lua_scheduler_add(lua_State *ps) {
84 lua_scheduler_entry *entry;
85 lua_scheduler *sched;
86
87 if(!lua_isuserdata(ps, 1) || !lua_isint(ps, 2) || !lua_isfunction(ps, 3))
88 return 0;
89
90 sched = (lua_scheduler *)lua_toscheduler(ps, 1);
91 if(!sched)
92 return 0;
93
94 entry = (lua_scheduler_entry *)malloc(sizeof(lua_scheduler_entry));
95 if(!entry)
96 return 0;
97
98 entry->ref = luaL_ref(ps, LUA_REGISTRYINDEX);
99 entry->sched = sched;
100 entry->psch = scheduleoneshot(lua_toint(ps, 2), scheduler_exec, entry);
101 if(!entry->psch) {
102 luaL_unref(ps, LUA_REGISTRYINDEX, entry->ref);
103 free(entry);
104 return 0;
105 }
106
107 entry->prev = NULL;
108 entry->next = sched->entries;
109
110 /* note: we have no tail pointer */
111
112 if(sched->entries)
113 sched->entries->prev = entry;
114
115 sched->entries = entry;
116 sched->count++;
117
118 lua_pushlightuserdata(ps, entry);
119 return 1;
120 }
121
122 static void delete_entry(lua_scheduler_entry *entry) {
123 deleteschedule(entry->psch, scheduler_exec, entry);
124 remove_entry(entry);
125 free_entry(entry);
126 }
127
128 static int lua_scheduler_remove(lua_State *ps) {
129 lua_scheduler_entry *entry;
130
131 if(!lua_islightuserdata(ps, 1))
132 LUA_RETURN(ps, LUA_FAIL);
133
134 entry = (lua_scheduler_entry *)lua_topointer(ps, 1);
135
136 if(!valid_entry(entry))
137 LUA_RETURN(ps, LUA_FAIL);
138
139 delete_entry(entry);
140
141 LUA_RETURN(ps, LUA_OK);
142 }
143
144 static int lua_scheduler_count(lua_State *ps) {
145 lua_scheduler *sched;
146
147 if(!lua_islightuserdata(ps, 1))
148 return 0;
149
150 sched = (lua_scheduler *)lua_topointer(ps, 1);
151 lua_pushint(ps, sched->count);
152
153 return 1;
154 }
155
156 static void scheduler_free(lua_list *ll, lua_scheduler *sched) {
157 lua_scheduler *prev, *l;
158
159 if(!sched->ps)
160 return;
161
162 while(sched->entries)
163 delete_entry(sched->entries);
164
165 for(prev=NULL,l=ll->schedulers;l;prev=l,l=l->next) {
166 if(l != sched)
167 continue;
168
169 if(prev) {
170 prev->next = sched->next;
171 } else {
172 ll->schedulers = sched->next;
173 }
174
175 break;
176 }
177
178 sched->ps = NULL;
179 }
180
181 void lua_scheduler_freeall(lua_list *ll) {
182 while(ll->schedulers)
183 scheduler_free(ll, ll->schedulers);
184 }
185
186 /* called at GC time only */
187 static int lua_scheduler_free(lua_State *ps) {
188 lua_list *ll = lua_listfromstate(ps);
189 lua_scheduler *sched;
190
191 if(!ll || !lua_isuserdata(ps, 1))
192 return 0;
193
194 sched = lua_toscheduler(ps, 1);
195 if(!sched)
196 return 0;
197
198 scheduler_free(ll, sched);
199
200 return 0;
201 }
202
203 void lua_registerschedulercommands(lua_State *ps) {
204 lua_register(ps, "raw_scheduler_new", lua_scheduler_new);
205 lua_register(ps, "raw_scheduler_count", lua_scheduler_count);
206 lua_register(ps, "raw_scheduler_add", lua_scheduler_add);
207 lua_register(ps, "raw_scheduler_remove", lua_scheduler_remove);
208
209 luaL_newmetatable(ps, SCHEDULER_METATABLE);
210 lua_pushcfunction(ps, lua_scheduler_free);
211 lua_setfield(ps, -2, "__gc");
212 }