diff --git a/src/async.c b/src/async.c index 5c2f190a..061e9f2c 100644 --- a/src/async.c +++ b/src/async.c @@ -54,14 +54,16 @@ static luv_async_send_t* luv_async_pop(luv_async_arg_t* asarg) { static luv_async_send_t* luv_async_push(luv_async_arg_t* asarg) { luv_async_send_t* sendarg = (luv_async_send_t*)malloc(sizeof(luv_async_send_t)); - memset(sendarg, 0, sizeof(luv_async_send_t)); - asarg->count++; - if (asarg->last != NULL) { - asarg->last->next = sendarg; - } - asarg->last = sendarg; - if (asarg->first == NULL) { - asarg->first = sendarg; + if (sendarg != NULL) { + memset(sendarg, 0, sizeof(luv_async_send_t)); + asarg->count++; + if (asarg->last != NULL) { + asarg->last->next = sendarg; + } + asarg->last = sendarg; + if (asarg->first == NULL) { + asarg->first = sendarg; + } } return sendarg; } @@ -154,25 +156,33 @@ static int luv_async_send(lua_State* L) { uv_async_t* handle = luv_check_async(L, 1); luv_async_arg_t* asarg = luv_get_async_arg_from_handle(handle); uv_mutex_t *argmutex = &asarg->mutex; - luv_thread_arg_t* args; - int n; + luv_thread_arg_t targcpy; + ret = luv_thread_arg_set(L, &targcpy, 2, lua_gettop(L), LUVF_THREAD_MODE_ASYNC|LUVF_THREAD_SIDE_CHILD); + if (ret < 0) { + luv_thread_arg_free(&targcpy); + return luv_thread_arg_error(L); + } uv_mutex_lock(argmutex); if (luv_is_async_queue(asarg)) { - if (asarg->count >= asarg->max) { + luv_async_send_t* sendarg = NULL; + ret = UV_ENOSPC; + if (asarg->count < asarg->max) { + sendarg = luv_async_push(asarg); + if (sendarg == NULL) { + ret = UV_ENOMEM; + } + } + if (sendarg == NULL) { uv_mutex_unlock(argmutex); - return luv_error(L, UV_ENOSPC); + luv_thread_arg_free(&targcpy); + return luv_error(L, ret); } - luv_async_send_t* sendarg = luv_async_push(asarg); - args = &sendarg->targ; + sendarg->targ = targcpy; } else { luv_thread_arg_free(&asarg->targ); // in case of a pending send - args = &asarg->targ; + asarg->targ = targcpy; } - n = luv_thread_arg_set(L, args, 2, lua_gettop(L), LUVF_THREAD_MODE_ASYNC|LUVF_THREAD_SIDE_CHILD); uv_mutex_unlock(argmutex); - if (n < 0) { - return luv_thread_arg_error(L); - } ret = uv_async_send(handle); return luv_result(L, ret); } diff --git a/src/thread.c b/src/thread.c index 7e752eb6..d8021d92 100644 --- a/src/thread.c +++ b/src/thread.c @@ -62,6 +62,13 @@ static const char* luv_getmtname(lua_State *L, int idx) { return name; } +static int luv_thread_arg_set_error(lua_State* L, luv_thread_arg_t* args, int type, int index) { + args->argc = index; + lua_pushinteger(L, type); + lua_pushinteger(L, index + 1); + return -1; +} + static int luv_thread_arg_set(lua_State* L, luv_thread_arg_t* args, int idx, int top, int flags) { int i; int side = LUVF_THREAD_SIDE(flags); @@ -72,7 +79,8 @@ static int luv_thread_arg_set(lua_State* L, luv_thread_arg_t* args, int idx, int args->flags = flags; while (i <= top && i < LUV_THREAD_MAXNUM_ARG + idx) { - luv_val_t *arg = args->argv + (i - idx); + int ii = i - idx; + luv_val_t *arg = args->argv + ii; arg->type = lua_type(L, i); arg->ref[0] = arg->ref[1] = LUA_NOREF; switch (arg->type) @@ -95,6 +103,9 @@ static int luv_thread_arg_set(lua_State* L, luv_thread_arg_t* args, int idx, int size_t l = 0; const char* p = lua_tolstring(L, i, &l); void* b = malloc(l + 1); + if (b == NULL) { + return luv_thread_arg_set_error(L, args, LUA_TNONE, ii); + } arg->val.str.base = memcpy((void*)b, p, l + 1); arg->val.str.len = l; } else { @@ -111,11 +122,17 @@ static int luv_thread_arg_set(lua_State* L, luv_thread_arg_t* args, int idx, int if (async) { if (l > 0) { void* b = malloc(l); + if (b == NULL) { + return luv_thread_arg_set_error(L, args, LUA_TNONE, ii); + } p = (const void*)memcpy(b, p, l); } if (mtname != NULL) { size_t ml = strlen(mtname) + 1; char* b = malloc(ml); + if (b == NULL) { + return luv_thread_arg_set_error(L, args, LUA_TNONE, ii); + } mtname = (const void*)memcpy(b, mtname, ml); } } else { @@ -128,10 +145,7 @@ static int luv_thread_arg_set(lua_State* L, luv_thread_arg_t* args, int idx, int } break; default: - args->argc = i - idx; - lua_pushinteger(L, arg->type); - lua_pushinteger(L, i - idx + 1); - return -1; + return luv_thread_arg_set_error(L, args, arg->type, ii); } i++; } @@ -251,6 +265,9 @@ static int luv_thread_arg_error(lua_State *L) { int type = lua_tointeger(L, -2); int pos = lua_tointeger(L, -1); lua_pop(L, 2); + if (type == LUA_TNONE) { + return luaL_error(L, "Error: thread arg failure at %d", pos); + } return luaL_error(L, "Error: thread arg not support type '%s' at %d", lua_typename(L, type), pos); } diff --git a/tests/test-async.lua b/tests/test-async.lua index 23c44d9c..d057ea53 100644 --- a/tests/test-async.lua +++ b/tests/test-async.lua @@ -28,7 +28,7 @@ return require('lib/tap')(function (test) end)) uv.new_thread(function(asy) assert(type(asy)=='userdata') - assert(asy:send('not ok')==0) -- will be ignored but its ok + assert(asy:send('not ok')==0) -- will be ignored but it's ok assert(asy:send('ok')==0) require('luv').sleep(10) end, async):join() @@ -62,8 +62,9 @@ return require('lib/tap')(function (test) assert(v=='ok') async:close() end)) - assert(async:send('not ok')==0) -- will be ignored but its ok + assert(async:send('not ok')==0) -- will be ignored but it's ok assert(async:send('ok')==0) + assert(pcall(uv.async_send, 'not ok', function() end)==false) -- will fail uv.run() end)