/
luv_handle.c
118 lines (99 loc) · 3.25 KB
/
luv_handle.c
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
/*
* Copyright 2012 The Luvit Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include <stdlib.h>
#include <assert.h>
#include "luv_handle.h"
/* Registers a callback, callback_index can't be negative */
void luv_register_event(lua_State* L, int userdata_index, const char* name, int callback_index) {
lua_getfenv(L, userdata_index);
lua_pushvalue(L, callback_index);
lua_setfield(L, -2, name);
lua_pop(L, 1);
}
/* Emit an event of the current userdata consuming nargs
* Assumes userdata is right below args
*/
void luv_emit_event(lua_State* L, const char* name, int nargs) {
/* Load the connection callback */
lua_getfenv(L, -nargs - 1);
lua_getfield(L, -1, name);
/* remove the userdata environment */
lua_remove(L, -2);
/* Remove the userdata */
lua_remove(L, -nargs - 2);
if (lua_isfunction (L, -1) == 0) {
lua_pop(L, 1 + nargs);
return;
}
/* move the function below the args */
lua_insert(L, -nargs - 1);
luv_acall(L, nargs, 0, name);
}
uv_buf_t luv_on_alloc(uv_handle_t* handle, size_t suggested_size) {
uv_buf_t buf;
buf.base = malloc(suggested_size);
buf.len = suggested_size;
return buf;
}
void luv_on_close(uv_handle_t* handle) {
/* printf("on_close\tlhandle=%p handle=%p\n", handle->data, handle);*/
/* load the lua state and the userdata */
luv_handle_t* lhandle = handle->data;
lua_State *L = lhandle->L;
lua_rawgeti(L, LUA_REGISTRYINDEX, lhandle->ref);
luv_emit_event(L, "close", 0);
luv_handle_unref(L, handle->data);
if (lhandle->ref != LUA_NOREF) {
assert(lhandle->refCount);
/* fprintf(stderr, "WARNING: closed %s with %d extra refs lhandle=%p handle=%p\n", lhandle->type, lhandle->refCount, handle->data, handle);*/
lhandle->refCount = 1;
luv_handle_unref(L, handle->data);
}
assert(lhandle->ref == LUA_NOREF);
/* This handle is no longer valid, clean up memory */
lhandle->handle = 0;
free(handle);
}
int luv_close (lua_State* L) {
uv_handle_t* handle = luv_checkudata(L, 1, "handle");
/* printf("close \tlhandle=%p handle=%p\n", handle->data, handle);*/
if (uv_is_closing(handle)) {
fprintf(stderr, "WARNING: Handle already closing \tlhandle=%p handle=%p\n", handle->data, handle);
return 0;
}
uv_close(handle, luv_on_close);
luv_handle_ref(L, handle->data, 1);
return 0;
}
int luv_ref(lua_State* L) {
uv_handle_t* handle = luv_checkudata(L, 1, "handle");
uv_ref(handle);
return 0;
}
int luv_unref(lua_State* L) {
uv_handle_t* handle = luv_checkudata(L, 1, "handle");
uv_unref(handle);
return 0;
}
int luv_set_handler(lua_State* L) {
const char* name;
luv_checkudata(L, 1, "handle");
name = luaL_checkstring(L, 2);
luaL_checktype(L, 3, LUA_TFUNCTION);
luv_register_event(L, 1, name, 3);
return 0;
}