]>
Commit | Line | Data |
---|---|---|
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 | } |