/* userdata send_buffer table pool lightuserdata msg int size return size Comment: The table pool record all the buffers chunk, and the first index [1] is a lightuserdata : free_node. We can always use this pointer for struct buffer_node . The following ([2] ...) userdatas in table pool is the buffer chunk (for struct buffer_node), we never free them until the VM closed. The size of first chunk ([2]) is 8 struct buffer_node, and the second size is 16 ... The largest size of chunk is LARGE_PAGE_NODE (4096) lpushbbuffer will get a free struct buffer_node from table pool, and then put the msg/size in it. lpopbuffer return the struct buffer_node back to table pool (By calling return_free_node). */ static int lpushbuffer(lua_State *L) { struct socket_buffer *sb = lua_touserdata(L,1); if (sb == NULL) { return luaL_error(L, "need buffer object at param 1"); } char * msg = lua_touserdata(L,3); if (msg == NULL) { return luaL_error(L, "need message block at param 3"); } int pool_index = 2; luaL_checktype(L,pool_index,LUA_TTABLE); int sz = luaL_checkinteger(L,4); lua_rawgeti(L,pool_index,1); struct buffer_node * free_node = lua_touserdata(L,-1); // sb poolt msg size free_node lua_pop(L,1); if (free_node == NULL) { int tsz = lua_rawlen(L,pool_index); if (tsz == 0) tsz++; int size = 8; if (tsz <= LARGE_PAGE_NODE-3) { size <<= tsz; } else { size <<= LARGE_PAGE_NODE-3; } lnewpool(L, size); free_node = lua_touserdata(L,-1); lua_rawseti(L, pool_index, tsz+1); } lua_pushlightuserdata(L, free_node->next); lua_rawseti(L, pool_index, 1); // sb poolt msg size free_node->msg = msg; free_node->sz = sz; free_node->next = NULL; if (sb->head == NULL) { assert(sb->tail == NULL); sb->head = sb->tail = free_node; } else { sb->tail->next = free_node; sb->tail = free_node; } sb->size += sz; lua_pushinteger(L, sb->size); return 1; }
// local sz = driver.push(s.buffer, buffer_pool, data, size) static int lpushbuffer(lua_State *L) { // 获取第一个参数值,缓冲区链表 struct socket_buffer *sb = lua_touserdata(L,1); if (sb == NULL) { return luaL_error(L, "need buffer object at param 1"); } // 获取第三个参数值,消息数据 char * msg = lua_touserdata(L,3); if (msg == NULL) { return luaL_error(L, "need message block at param 3"); } int pool_index = 2; // 检查第二个参数是否为table类型 /* local buffer_pool = {} buffer_pool是在lua层(socket.lua)中创建并初始化空表 lua方法pop,push,readall,readline,clear中作为第二个参数传入 在lua绑定的c方法中,从栈中取出第二个元素,即可得到buffer_pool buffer_pool[1],存放的是一个lightuserdata,即缓冲区池第一个节点的地址,见lua_pushlightuserdata(L, free_node->next); buffer_pool[2] ...,存放的是userdata,即固定大小的链表数组内存地址,见lua_rawseti(L, pool_index, tsz+1); */ luaL_checktype(L,pool_index,LUA_TTABLE); // 获取第四个参数值,消息长度 int sz = luaL_checkinteger(L,4); // 把缓冲池lua表的第一个元素压栈 lua_rawgeti(L,pool_index,1); // 获取缓冲池lua表的第一个元素 // 准确地说是 获取第一个元素存放的指针 所指向的一段完全用户数据 其实就是一个缓冲区节点 struct buffer_node * free_node = lua_touserdata(L,-1); // sb poolt msg size free_node // 把缓冲池lua表的第一个元素弹出栈 lua_pop(L,1); if (free_node == NULL) { // 如果获取到的缓冲区节点为空,说明buffer_pool[n]里的buffer_node已经用光 // 获取buffer_pool表的长度 // 初始为0,一直递增,直到vm重启 /* tsz buffer_pool表的长度 index buffer_pool表的索引 size buffer_pool[index]存放buffer_node的数量 tsz size index 0 8 << 1 = 16 2 2 8 << 2 = 32 3 . . . 9 8 << 9 = 4096 10 10 8 << 9 = 4096 11 */ int tsz = lua_rawlen(L,pool_index); if (tsz == 0) // 初始为0,预留buffer_pool[1]存放lightuserdata tsz++; int size = 8; if (tsz <= LARGE_PAGE_NODE-3) { size <<= tsz; } else { // 不超过4096,即2的12次方 size <<= LARGE_PAGE_NODE-3; } // 新建缓冲区池 // struct buffer_node * pool = lua_newuserdata(L, sizeof(struct buffer_node) * sz); lnewpool(L, size); // 获取新建缓冲区池第一个缓冲区节点 free_node = lua_touserdata(L,-1); // 把新建的缓冲区池放到缓冲区池lua表的特定索引中 lua_rawseti(L, pool_index, tsz+1); } // 把缓冲池lua表的第一个元素的下一个元素压栈 lua_pushlightuserdata(L, free_node->next); // 把缓冲池lua表的第一个元素的下一个元素设置为lua表的第一个元素,并弹出栈 lua_rawseti(L, pool_index, 1); // sb poolt msg size // 以上操作从缓冲池中取出了一个缓冲区节点 // 缓冲区节点装入数据 free_node->msg = msg; free_node->sz = sz; free_node->next = NULL; // 缓冲区节点加入链表 if (sb->head == NULL) { assert(sb->tail == NULL); sb->head = sb->tail = free_node; } else { sb->tail->next = free_node; sb->tail = free_node; } sb->size += sz; // 缓冲区链表数据总长度压栈并作为lua返回值 lua_pushinteger(L, sb->size); return 1; }