/* initialize lua coroutine for fetching cached session */
static ngx_int_t
ngx_http_lua_ssl_sess_fetch_by_chunk(lua_State *L, ngx_http_request_t *r)
{
    int                      co_ref;
    ngx_int_t                rc;
    lua_State               *co;
    ngx_http_lua_ctx_t      *ctx;
    ngx_http_cleanup_t      *cln;

    ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);

    if (ctx == NULL) {
        ctx = ngx_http_lua_create_ctx(r);
        if (ctx == NULL) {
            rc = NGX_ERROR;
            ngx_http_lua_finalize_request(r, rc);
            return rc;
        }

    } else {
        dd("reset ctx");
        ngx_http_lua_reset_ctx(r, L, ctx);
    }

    ctx->entered_content_phase = 1;

    /*  {{{ new coroutine to handle request */
    co = ngx_http_lua_new_thread(r, L, &co_ref);

    if (co == NULL) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "lua: failed to create new coroutine to handle request");

        rc = NGX_ERROR;
        ngx_http_lua_finalize_request(r, rc);
        return rc;
    }

    /*  move code closure to new coroutine */
    lua_xmove(L, co, 1);

    /*  set closure's env table to new coroutine's globals table */
    ngx_http_lua_get_globals_table(co);
    lua_setfenv(co, -2);

    /* save nginx request in coroutine globals table */
    ngx_http_lua_set_req(co, r);

    ctx->cur_co_ctx = &ctx->entry_co_ctx;
    ctx->cur_co_ctx->co = co;
    ctx->cur_co_ctx->co_ref = co_ref;
#ifdef NGX_LUA_USE_ASSERT
    ctx->cur_co_ctx->co_top = 1;
#endif

    /* register request cleanup hooks */
    if (ctx->cleanup == NULL) {
        cln = ngx_http_cleanup_add(r, 0);
        if (cln == NULL) {
            rc = NGX_ERROR;
            ngx_http_lua_finalize_request(r, rc);
            return rc;
        }

        cln->handler = ngx_http_lua_request_cleanup_handler;
        cln->data = ctx;
        ctx->cleanup = &cln->handler;
    }

    ctx->context = NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH;

    rc = ngx_http_lua_run_thread(L, r, ctx, 0);

    if (rc == NGX_ERROR || rc >= NGX_OK) {
        /* do nothing */

    } else if (rc == NGX_AGAIN) {
        rc = ngx_http_lua_content_run_posted_threads(L, r, ctx, 0);

    } else if (rc == NGX_DONE) {
        rc = ngx_http_lua_content_run_posted_threads(L, r, ctx, 1);

    } else {
        rc = NGX_OK;
    }

    ngx_http_lua_finalize_request(r, rc);
    return rc;
}
Пример #2
0
ngx_int_t
ngx_http_lua_content_by_chunk(lua_State *L, ngx_http_request_t *r)
{
    int                      cc_ref;
    lua_State               *cc;
    ngx_http_lua_ctx_t      *ctx;
    ngx_http_cleanup_t      *cln;

    dd("content by chunk");

    ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);

    if (ctx == NULL) {
        ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_lua_ctx_t));
        if (ctx == NULL) {
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

        dd("setting new ctx, ctx = %p", ctx);

        ctx->cc_ref = LUA_NOREF;
        ctx->ctx_ref = LUA_NOREF;

        ngx_http_set_ctx(r, ctx, ngx_http_lua_module);

    } else {
        dd("reset ctx");
        ngx_http_lua_reset_ctx(r, L, ctx);
    }

    ctx->entered_content_phase = 1;

    /*  {{{ new coroutine to handle request */
    cc = ngx_http_lua_new_thread(r, L, &cc_ref);

    if (cc == NULL) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                "(lua-content-by-chunk) failed to create new coroutine "
                "to handle request");

        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    /*  move code closure to new coroutine */
    lua_xmove(L, cc, 1);

    /*  set closure's env table to new coroutine's globals table */
    lua_pushvalue(cc, LUA_GLOBALSINDEX);
    lua_setfenv(cc, -2);

    /*  save reference of code to ease forcing stopping */
    lua_pushvalue(cc, -1);
    lua_setglobal(cc, GLOBALS_SYMBOL_RUNCODE);

    /*  save nginx request in coroutine globals table */
    lua_pushlightuserdata(cc, r);
    lua_setglobal(cc, GLOBALS_SYMBOL_REQUEST);
    /*  }}} */

    ctx->cc = cc;
    ctx->cc_ref = cc_ref;

    /*  {{{ register request cleanup hooks */
    if (ctx->cleanup == NULL) {
        cln = ngx_http_cleanup_add(r, 0);
        if (cln == NULL) {
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

        cln->handler = ngx_http_lua_request_cleanup;
        cln->data = r;
        ctx->cleanup = &cln->handler;
    }
    /*  }}} */

    return ngx_http_lua_run_thread(L, r, ctx, 0);
}
ngx_int_t
ngx_http_lua_content_by_chunk(lua_State *L, ngx_http_request_t *r)
{
    int                      co_ref;
    ngx_int_t                rc;
    lua_State               *co;
    ngx_http_lua_ctx_t      *ctx;
    ngx_http_cleanup_t      *cln;

    dd("content by chunk");

    ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);

    if (ctx == NULL) {
        ctx = ngx_http_lua_create_ctx(r);
        if (ctx == NULL) {
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

    } else {
        dd("reset ctx");
        ngx_http_lua_reset_ctx(r, L, ctx);
    }

    ctx->entered_content_phase = 1;

    /*  {{{ new coroutine to handle request */
    co = ngx_http_lua_new_thread(r, L, &co_ref);

    if (co == NULL) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                     "lua: failed to create new coroutine to handle request");

        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    /*  move code closure to new coroutine */
    lua_xmove(L, co, 1);

    /*  set closure's env table to new coroutine's globals table */
    lua_pushvalue(co, LUA_GLOBALSINDEX);
    lua_setfenv(co, -2);

    /*  save nginx request in coroutine globals table */
    lua_pushlightuserdata(co, &ngx_http_lua_request_key);
    lua_pushlightuserdata(co, r);
    lua_rawset(co, LUA_GLOBALSINDEX);
    /*  }}} */

    ctx->cur_co_ctx = &ctx->entry_co_ctx;
    ctx->cur_co_ctx->co = co;
    ctx->cur_co_ctx->co_ref = co_ref;

    /*  {{{ register request cleanup hooks */
    if (ctx->cleanup == NULL) {
        cln = ngx_http_cleanup_add(r, 0);
        if (cln == NULL) {
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

        cln->handler = ngx_http_lua_request_cleanup;
        cln->data = r;
        ctx->cleanup = &cln->handler;
    }
    /*  }}} */

    ctx->context = NGX_HTTP_LUA_CONTEXT_CONTENT;

    rc = ngx_http_lua_run_thread(L, r, ctx, 0);

    if (rc == NGX_ERROR || rc >= NGX_OK) {
        return rc;
    }

    if (rc == NGX_AGAIN) {
        return ngx_http_lua_content_run_posted_threads(L, r, ctx, 0);
    }

    if (rc == NGX_DONE) {
        return ngx_http_lua_content_run_posted_threads(L, r, ctx, 1);
    }

    return NGX_OK;
}
Пример #4
0
static int
emit (lua_State *L)
{
   lyaml_emitter *emitter;
   int yaml_ok = 0;
   int finalize = 0;

   luaL_argcheck (L, lua_istable (L, 1), 1, "expected table");

   emitter = (lyaml_emitter *) lua_touserdata (L, lua_upvalueindex (1));

   {
     const char *type;

     RAWGET_STRDUP (type); lua_pop (L, 1);

     if (type == NULL)
     {
        emitter->error++;
        luaL_addstring (&emitter->errbuff, "no type field in event table");
     }
#define MENTRY(_s) (STREQ (type, #_s)) { yaml_ok = emit_##_s (L, emitter); }
     /* Minimize comparisons by putting more common types earlier. */
     else if MENTRY( SCALAR		)
     else if MENTRY( MAPPING_START	)
     else if MENTRY( MAPPING_END	)
     else if MENTRY( SEQUENCE_START	)
     else if MENTRY( SEQUENCE_END	)
     else if MENTRY( DOCUMENT_START	)
     else if MENTRY( DOCUMENT_END	)
     else if MENTRY( STREAM_START	)
     else if MENTRY( STREAM_END		)
     else if MENTRY( ALIAS		)
#undef MENTRY
     else
     {
        emitter->error++;
        luaL_addsize (&emitter->errbuff,
                      sprintf (luaL_prepbuffer (&emitter->errbuff),
                               "invalid event type '%s'", type));
     }

     /* If the stream has finished, finalize the YAML output. */
     if (type && STREQ (type, "STREAM_END"))
       finalize = 1;

     if (type) free ((void *) type);
   }

   /* Copy any yaml_emitter_t errors into the error buffer. */
   if (!emitter->error && !yaml_ok)
   {
      if (emitter->emitter.problem)
        luaL_addstring (&emitter->errbuff, emitter->emitter.problem);
      else
        luaL_addstring (&emitter->errbuff, "LibYAML call failed");
      emitter->error++;
   }

   /* Report errors back to the caller as `false, "error message"`. */
   if (emitter->error != 0)
   {
      assert (emitter->error == 1);  /* bail on uncaught additional errors */
      lua_pushboolean (L, 0);
      luaL_pushresult (&emitter->errbuff);
      lua_xmove (emitter->errL, L, 1);
      return 2;
   }

   /* Return `true, "YAML string"` after accepting a STREAM_END event. */
   if (finalize)
   {
      lua_pushboolean (L, 1);
      luaL_pushresult (&emitter->yamlbuff);
      lua_xmove (emitter->outputL, L, 1);
      return 2;
   }

   /* Otherwise, just report success to the caller as `true`. */
   lua_pushboolean (L, 1);
   return 1;
}
Пример #5
0
/*
 * Arguments: evq_udata,
 *	obj_udata | signal (number),
 *	events (string: "r", "w") | event_flags (number),
 *	callback (function | coroutine),
 *	[timeout (milliseconds), one_shot (boolean)]
 * Returns: [ev_ludata]
 */
static int
levq_add (lua_State *L)
{
    struct event_queue *evq = checkudata(L, 1, EVQ_TYPENAME);
    unsigned int ev_flags = lua_tointeger(L, 3)
     | (lua_toboolean(L, 6) ? EVENT_ONESHOT : 0);
    const msec_t timeout = lua_isnoneornil(L, 5)
     ? TIMEOUT_INFINITE : (msec_t) lua_tointeger(L, 5);
    struct event *ev;
    int res;

#undef ARG_LAST
#define ARG_LAST	4

    ev = levq_new_event(evq);

    if (!(ev_flags & EVENT_TIMER)) {
	fd_t *fdp = lua_touserdata(L, 2);
	ev->fd = fdp ? *fdp
	 : (fd_t) lua_tointeger(L, 2);  /* signo */
    }

    if (!(ev_flags & (EVENT_READ | EVENT_WRITE))) {
	const char *evstr = lua_tostring(L, 3);

	ev_flags |= (!evstr || evstr[0] == 'r')
	 ? EVENT_READ : EVENT_WRITE;
    }

    switch (lua_type(L, 4)) {
    case LUA_TFUNCTION:
	ev_flags |= EVENT_CALLBACK;
	break;
    case LUA_TTHREAD:
	ev_flags |= EVENT_CALLBACK | EVENT_CALLBACK_CORO;
	break;
    }

    ev->flags = ev_flags;

    /* reserve place for timeout_queue */
    if (!evq->ev_free)
	evq->ev_free = levq_new_event(evq);

    if (ev_flags & EVENT_TIMER) {
	res = evq_add_timer(evq, ev, timeout);
    } else {
	if (ev_flags & EVENT_DIRWATCH) {
	    const char *path = luaL_checkstring(L, 2);
	    res = evq_add_dirwatch(evq, ev, path);
	} else {
	    res = evq_add(evq, ev);
	}

	if (!res && timeout != TIMEOUT_INFINITE) {
	    evq_set_timeout(ev, timeout);
	}
    }
    if (!res) {
	lua_State *NL = evq->L;
	const int ev_id = ev->ev_id;

	/* cb_fun */
	if (ev_flags & EVENT_CALLBACK) {
	    lua_settop(L, 4);
	    lua_xmove(L, NL, 1);
	    lua_rawseti(NL, EVQ_CORO_CALLBACK, ev_id);
	}
	/* obj_udata */
	lua_settop(L, 2);
	lua_xmove(L, NL, 1);
	lua_rawseti(NL, EVQ_CORO_UDATA, ev_id);

	lua_pushlightuserdata(L, ev);
	return 1;
    }
    levq_del_event(evq, ev);
    return sys_seterror(L, 0);
}
Пример #6
0
/*
 * open()
 *
 * argument 1: uri to connect to
 */
static int
bus_open(lua_State *T)
{
	const char *uri;
	DBusError err;
	DBusConnection *conn;
	struct bus_object *obj;
	lua_State *S;

	uri = luaL_checkstring(T, 1);
	lem_debug("opening %s", uri);

	dbus_error_init(&err);
	conn = dbus_connection_open_private(uri, &err);

	if (dbus_error_is_set(&err)) {
		lua_pushnil(T);
		lua_pushstring(T, err.message);
		dbus_error_free(&err);
		return 2;
	}

	if (conn == NULL) {
		lua_pushnil(T);
		lua_pushliteral(T, "error opening connection");
		return 2;
	}

	dbus_connection_set_exit_on_disconnect(conn, FALSE);

	/* set watch functions */
	if (!dbus_connection_set_watch_functions(conn,
	                                         watch_add,
	                                         watch_remove,
	                                         watch_toggle,
	                                         conn, NULL)) {
		dbus_connection_close(conn);
		dbus_connection_unref(conn);
		lua_pushnil(T);
		lua_pushliteral(T, "error setting watch functions");
		return 2;
	}

	/* set timout functions */
	if (!dbus_connection_set_timeout_functions(conn,
	                                           timeout_add,
	                                           timeout_remove,
	                                           timeout_toggle,
	                                           conn, NULL)) {
		dbus_connection_close(conn);
		dbus_connection_unref(conn);
		lua_pushnil(T);
		lua_pushliteral(T, "error setting timeout functions");
		return 2;
	}

	/* create new userdata for the bus */
	obj = lua_newuserdata(T, sizeof(struct bus_object));
	obj->conn = conn;

	/* set the metatable */
	lua_pushvalue(T, lua_upvalueindex(1));
	lua_setmetatable(T, -2);

	/* create fenv table */
	lua_createtable(T, 2, 0);

	/* create signal handler thread */
	S = lua_newthread(T);
	lua_rawseti(T, -2, 1);

	/* put a reference to bus object and
	 * message metatable on thread */
	lua_pushvalue(T, -2);
	lua_pushvalue(T, lua_upvalueindex(2));
	lua_xmove(T, S, 2);

	/* create signal handler table */
	lua_newtable(S);
	lua_pushvalue(S, -1);
	lua_xmove(S, T, 1);
	lua_rawseti(T, -2, 2);

	/* create object path table */
	lua_newtable(S);
	lua_pushvalue(S, -1);
	lua_xmove(S, T, 1);
	lua_rawseti(T, -2, 3);

	/* set fenv table */
	lua_setfenv(T, -2);

	/* set the message filter */
	if (!dbus_connection_add_filter(conn, message_filter, S, NULL)) {
		dbus_connection_close(conn);
		dbus_connection_unref(conn);
		lua_pushnil(T);
		lua_pushliteral(T, "out of memory");
		return 2;
	}

	/* return the bus object */
	return 1;
}
Пример #7
0
// Помещает на верхушку стека значенее из реестра
void LuaScript::GetFromRegistry( lua_State* L, LuaRegRef r )
{
	lua_rawgeti( Lst, LUA_REGISTRYINDEX, r );
	lua_xmove( Lst, L, 1 );
}
Пример #8
0
static int
ngx_http_lua_ngx_timer_at(lua_State *L)
{
    int                      nargs, co_ref;
    u_char                  *p;
    lua_State               *vm;  /* the main thread */
    lua_State               *co;
    ngx_msec_t               delay;
    ngx_event_t             *ev;
    ngx_http_request_t      *r;
    ngx_connection_t        *saved_c = NULL;
    ngx_http_lua_ctx_t      *ctx;
#if 0
    ngx_http_connection_t   *hc;
#endif

    ngx_http_lua_timer_ctx_t      *tctx;
    ngx_http_lua_main_conf_t      *lmcf;
#if 0
    ngx_http_core_main_conf_t     *cmcf;
#endif

    nargs = lua_gettop(L);
    if (nargs < 2) {
        return luaL_error(L, "expecting at least 2 arguments but got %d",
                          nargs);
    }

    delay = (ngx_msec_t) (luaL_checknumber(L, 1) * 1000);

    luaL_argcheck(L, lua_isfunction(L, 2) && !lua_iscfunction(L, 2), 2,
                 "Lua function expected");

    r = ngx_http_lua_get_req(L);
    if (r == NULL) {
        return luaL_error(L, "no request");
    }

    ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);

    if (ngx_exiting && delay > 0) {
        lua_pushnil(L);
        lua_pushliteral(L, "process exiting");
        return 2;
    }

    lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module);

    if (lmcf->pending_timers >= lmcf->max_pending_timers) {
        lua_pushnil(L);
        lua_pushliteral(L, "too many pending timers");
        return 2;
    }

    if (lmcf->watcher == NULL) {
        /* create the watcher fake connection */

        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
                       "lua creating fake watcher connection");

        if (ngx_cycle->files) {
            saved_c = ngx_cycle->files[0];
        }

        lmcf->watcher = ngx_get_connection(0, ngx_cycle->log);

        if (ngx_cycle->files) {
            ngx_cycle->files[0] = saved_c;
        }

        if (lmcf->watcher == NULL) {
            return luaL_error(L, "no memory");
        }

        /* to work around the -1 check in ngx_worker_process_cycle: */
        lmcf->watcher->fd = (ngx_socket_t) -2;

        lmcf->watcher->idle = 1;
        lmcf->watcher->read->handler = ngx_http_lua_abort_pending_timers;
        lmcf->watcher->data = lmcf;
    }

    vm = ngx_http_lua_get_lua_vm(r, ctx);

    co = lua_newthread(vm);

    /* L stack: time func [args] thread */

    ngx_http_lua_probe_user_coroutine_create(r, L, co);

    lua_createtable(co, 0, 0);  /* the new global table */

    /* co stack: global_tb */

    lua_createtable(co, 0, 1);  /* the metatable */
    lua_pushvalue(co, LUA_GLOBALSINDEX);
    lua_setfield(co, -2, "__index");
    lua_setmetatable(co, -2);

    /* co stack: global_tb */

    lua_replace(co, LUA_GLOBALSINDEX);

    /* co stack: <empty> */

    dd("stack top: %d", lua_gettop(L));

    lua_xmove(vm, L, 1);    /* move coroutine from main thread to L */

    /* L stack: time func [args] thread */
    /* vm stack: empty */

    lua_pushvalue(L, 2);    /* copy entry function to top of L*/

    /* L stack: time func [args] thread func */

    lua_xmove(L, co, 1);    /* move entry function from L to co */

    /* L stack: time func [args] thread */
    /* co stack: func */

    lua_pushvalue(co, LUA_GLOBALSINDEX);
    lua_setfenv(co, -2);

    /* co stack: func */

    lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key);
    lua_rawget(L, LUA_REGISTRYINDEX);

    /* L stack: time func [args] thread corountines */

    lua_pushvalue(L, -2);

    /* L stack: time func [args] thread coroutines thread */

    co_ref = luaL_ref(L, -2);
    lua_pop(L, 1);

    /* L stack: time func [args] thread */

    if (nargs > 2) {
        lua_pop(L, 1);  /* L stack: time func [args] */
        lua_xmove(L, co, nargs - 2);  /* L stack: time func */

        /* co stack: func [args] */
    }

    p = ngx_alloc(sizeof(ngx_event_t) + sizeof(ngx_http_lua_timer_ctx_t),
                  r->connection->log);
    if (p == NULL) {
        lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key);
        lua_rawget(L, LUA_REGISTRYINDEX);
        luaL_unref(L, -1, co_ref);
        return luaL_error(L, "no memory");
    }

    ev = (ngx_event_t *) p;

    ngx_memzero(ev, sizeof(ngx_event_t));

    p += sizeof(ngx_event_t);

    tctx = (ngx_http_lua_timer_ctx_t *) p;

    tctx->premature = 0;
    tctx->co_ref = co_ref;
    tctx->co = co;
    tctx->main_conf = r->main_conf;
    tctx->srv_conf = r->srv_conf;
    tctx->loc_conf = r->loc_conf;
    tctx->lmcf = lmcf;

    if (ctx && ctx->vm_state) {
        tctx->vm_state = ctx->vm_state;
        tctx->vm_state->count++;

    } else {
        tctx->vm_state = NULL;
    }

    ev->handler = ngx_http_lua_timer_handler;
    ev->data = tctx;
    ev->log = ngx_cycle->log;

    lmcf->pending_timers++;

    ngx_add_timer(ev, delay);

    lua_pushinteger(L, 1);
    return 1;
}
Пример #9
0
/*
 * Arguments: dpool_udata, [timeout (milliseconds)]
 * Returns: data_items (any) ...
 */
static int
dpool_get (lua_State *L)
{
    struct sys_thread *td = sys_thread_get();
    struct data_pool *dp = checkudata(L, 1, DPOOL_TYPENAME);
    const msec_t timeout = lua_isnoneornil(L, 2)
     ? TIMEOUT_INFINITE : (msec_t) lua_tointeger(L, 2);
    int nput;

    if (!td) luaL_argerror(L, 0, "Threading not initialized");

    lua_settop(L, 1);
    lua_getfenv(L, 1);  /* storage */
    lua_insert(L, 1);

    if ((dp->flags & DPOOL_GETONEMPTY) && !dp->n) {
	lua_rawgetp(L, 1, (void *) DPOOL_GETONEMPTY);
	lua_insert(L, 2);
	lua_call(L, 1, LUA_MULTRET);
	nput = lua_gettop(L) - 1;
	if (nput) return nput;
    }

    for (; ; ) {
	/* get from storage */
	if (dp->n) {
	    const int idx = dp->idx + 1;
	    int i;

	    lua_rawgeti(L, 1, idx);
	    nput = lua_tointeger(L, -1);
	    lua_pushnil(L);
	    lua_rawseti(L, 1, idx);
	    dp->idx = idx + nput;
	    for (i = dp->idx; i > idx; --i) {
		lua_rawgeti(L, 1, i);
		lua_pushnil(L);
		lua_rawseti(L, 1, i);
	    }
	    if (dp->idx == dp->top)
		dp->idx = dp->top = 0;
	    if (dp->n-- == dp->max) {
		thread_event_signal(&dp->tev);
	    }
	    return nput;
	}

	/* wait signal */
	{
	    int res;

	    dp->nwaits++;
	    res = thread_event_wait(&dp->tev, td, timeout);
	    dp->nwaits--;

	    sys_thread_check(td);
	    if (res) {
		if (res == 1) {
		    lua_pushboolean(L, 0);
		    return 1;  /* timed out */
		}
		return sys_seterror(L, 0);
	    }
	}

	/* get directly from another thread */
	nput = dp->nput;
	if (nput) {
	    dp->nput = 0;
	    luaL_checkstack(L, nput, NULL);
	    lua_xmove(dp->td->L, L, nput);
	    return nput;
	}
    }
}
Пример #10
0
/*
 * Arguments: function, [arguments (any) ...]
 * Returns: [thread_ludata]
 */
static int
thread_run (lua_State *L)
{
    struct sys_thread *vmtd = sys_get_thread();
    lua_State *NL;
    struct sys_thread *td;
#ifndef _WIN32
    pthread_attr_t attr;
    int res = 0;
#else
    HANDLE hThr;
    const int res = 0;
#endif

    if (!vmtd) luaL_argerror(L, 0, "Threading not initialized");
    luaL_checktype(L, 1, LUA_TFUNCTION);

    NL = lua_newthread(L);
    if (!NL) goto err;

    td = lua_newuserdata(L, sizeof(struct sys_thread));
    memset(td, 0, sizeof(struct sys_thread));
    td->mutex = vmtd->mutex;
    td->L = NL;
    td->vmtd = vmtd->vmtd;

#ifndef _WIN32
    if ((res = pthread_attr_init(&attr))
     || (res = pthread_attr_setstacksize(&attr, THREAD_STACK_SIZE)))
	goto err;
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

    res = pthread_create(&td->tid, &attr,
     (thread_func_t) thread_start, td);
    pthread_attr_destroy(&attr);
    if (!res) {
#else
    hThr = (HANDLE) _beginthreadex(NULL, THREAD_STACK_SIZE,
     (thread_func_t) thread_start, td, 0, &td->tid);
    if (hThr) {
	CloseHandle(hThr);
#endif
	thread_settable(L, NL, td->tid);  /* save thread to avoid GC */
	lua_xmove(L, NL, lua_gettop(L));  /* move function and args to NL */

	lua_pushlightuserdata(L, td);
	return 1;
    }
 err:
    return sys_seterror(L, res);
}


/*
 * Arguments: function, master (thread_ludata),
 *	[arguments (string | number | boolean | lightuserdata) ...],
 *	thread, thread_udata
 */
static THREAD_FUNC_API
thread_startvm (struct sys_thread *td)
{
    lua_State *L = td->L;

    thread_settable(L, L, td->tid);

    sys_set_thread(td);
    sys_vm2_enter(td);

    if (lua_pcall(L, lua_gettop(L) - 1, 0, 0)) {
	if (td->interrupted && lua_touserdata(L, -1) == &g_TLSIndex)
	    lua_pop(L, 1);
	else
	    lua_error(L);
    }

    /* notify event_queue */
    if (td->trigger)
	sys_trigger_notify(&td->trigger, SYS_EVEOF | SYS_EVDEL);

    lua_close(L);
    return 0;
}
Пример #11
0
static void *cothread( void *arg )
{
    lpthread_t *th = (lpthread_t*)arg;
    lua_State *L = lua_newthread( th->L );
    int ref = lstate_ref( th->L );
    lua_State *task = th->task.L;

    th->join = 0;
    // wakeup parent
    pthread_cond_signal( &CREATION_COND );

    lpth_lock( th );

WAIT_COTHREAD:
    pthread_cond_wait( &th->cond, &th->mutex );
    if( !th->join )
    {
        lua_State *co = NULL;
        lua_State *eco = NULL;
        int argc = 0;

CHECK_TASK:
        lpth_task_lock( th );
        // get task
        if( lua_gettop( task ) )
        {
            lua_pushvalue( task, 1 );
            lua_xmove( task, L, 1 );
            lua_remove( task, 1 );
            co = lua_tothread( L, -1 );
            argc = lua_gettop( co );
            // create error thread
            if( argc > 1 && lua_type( co, 2 ) == LUA_TFUNCTION )
            {
                if( ( eco = lua_newthread( L ) ) )
                {
                    int i = 2;

                    for(; i <= argc; i++ ){
                        lua_pushvalue( co, i );
                    }
                    lua_xmove( co, eco, argc - 1 );
                }
                // remove error function
                lua_remove( co, 2 );
            }
        }
        lpth_task_unlock( th );

        if( co )
        {
            switch( lua_resume( co, lua_gettop( co ) - 1 ) )
            {
                case LUA_YIELD:
                case LUA_ERRRUN:
                case LUA_ERRSYNTAX:
                case LUA_ERRMEM:
                case LUA_ERRERR:
                    if( eco ){
                        lua_xmove( co, eco, 1 );
                        lua_insert( eco, 2 );
                        lua_resume( eco, argc - 1 );
                    }
                break;
            }

            // remove coroutine
            lua_settop( L, 0 );
            if( !th->join ){
                co = eco = NULL;
                goto CHECK_TASK;
            }
        }
        else if( !th->join ){
            goto WAIT_COTHREAD;
        }
    }

    lpth_unlock( th );
    lstate_unref( th->L, ref );

    return NULL;
}
Пример #12
0
static int db_getinfo (lua_State *L) {
  lua_Debug ar;
  int arg;
  //add by cuiwei 07.8.30
  int i;
  char aparms[1024] = {0};
  //add end
  lua_State *L1 = getthread(L, &arg);
  const char *options = luaL_optstring(L, arg+2, "flnSu");
  if (lua_isnumber(L, arg+1)) {
    if (!lua_getstack(L1, (int)lua_tointeger(L, arg+1), &ar)) {
      lua_pushnil(L);  /* level out of range */
      return 1;
    }
  }
  else if (lua_isfunction(L, arg+1)) {
    lua_pushfstring(L, ">%s", options);
    options = lua_tostring(L, -1);
    lua_pushvalue(L, arg+1);
    lua_xmove(L, L1, 1);
  }
  else
    return luaL_argerror(L, arg+1, "function or level expected");
  if (!lua_getinfo(L1, options, &ar))
    return luaL_argerror(L, arg+2, "invalid option");
  lua_createtable(L, 0, 2);
  if (strchr(options, 'S')) {
    settabss(L, "source", ar.source);
    settabss(L, "short_src", ar.short_src);
    settabsi(L, "linedefined", ar.linedefined);
    settabsi(L, "lastlinedefined", ar.lastlinedefined);
    settabss(L, "what", ar.what);
  }
  if (strchr(options, 'l'))
    settabsi(L, "currentline", ar.currentline);
  if (strchr(options, 'u'))
  {
    settabsi(L, "nups", ar.nups);
	//add by cuiwei 07.8.30
	if (ar.what != "C" )
	{
		settabsi(L, "npars", ar.npars);
		settabsi(L, "has3dot", ar.has3dot?1:0);
		for ( i = 1; i <= ar.npars; i++ )
		{
			strcat(aparms, ar.parms[i-1]);
			if ( i != ar.npars || ar.has3dot)
			{
				strcat(aparms, ",");
			}
		}
		if ( ar.has3dot )
		{
			strcat(aparms, "...");
		}	settabss(L, "strparms", aparms);
	}
	//add end
  }
  if (strchr(options, 'n')) {
    settabss(L, "name", ar.name);
    settabss(L, "namewhat", ar.namewhat);
  }
  if (strchr(options, 'L'))
    treatstackoption(L, L1, "activelines");
  if (strchr(options, 'f'))
    treatstackoption(L, L1, "func");
  return 1;  /* return table */
}
Пример #13
0
	void LuaInstance::MoveTo(LuaInstance* instance, int n) const
	{
		lua_xmove(m_state, instance->m_state, n);
	}
Пример #14
0
static int
ngx_http_lua_uthread_wait(lua_State *L)
{
    int                          i, nargs, nrets;
    lua_State                   *sub_co;
    ngx_http_request_t          *r;
    ngx_http_lua_ctx_t          *ctx;
    ngx_http_lua_co_ctx_t       *coctx, *sub_coctx;

    r = ngx_http_lua_get_req(L);
    if (r == NULL) {
        return luaL_error(L, "no request found");
    }

    ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
    if (ctx == NULL) {
        return luaL_error(L, "no request ctx found");
    }

    ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE
                               | NGX_HTTP_LUA_CONTEXT_ACCESS
                               | NGX_HTTP_LUA_CONTEXT_CONTENT
                               | NGX_HTTP_LUA_CONTEXT_TIMER);

    coctx = ctx->cur_co_ctx;

    nargs = lua_gettop(L);

    for (i = 1; i <= nargs; i++) {
        sub_co = lua_tothread(L, i);

        luaL_argcheck(L, sub_co, i, "lua thread expected");

        sub_coctx = ngx_http_lua_get_co_ctx(sub_co, ctx);
        if (sub_coctx == NULL) {
            goto found_dead;
        }

        if (!sub_coctx->is_uthread) {
            return luaL_error(L, "attempt to wait on a coroutine that is "
                              "not a user thread");
        }

        if (sub_coctx->parent_co_ctx != coctx) {
            return luaL_error(L, "only the parent coroutine can wait on the "
                              "thread");
        }

        switch (sub_coctx->co_status) {
        case NGX_HTTP_LUA_CO_ZOMBIE:

            ngx_http_lua_probe_info("found zombie child");

            nrets = lua_gettop(sub_coctx->co);

            dd("child retval count: %d, %s: %s", (int) nrets,
               luaL_typename(sub_coctx->co, -1),
               lua_tostring(sub_coctx->co, -1));

            if (nrets) {
                lua_xmove(sub_coctx->co, L, nrets);
            }

#if 1
            ngx_http_lua_del_thread(r, L, ctx, sub_coctx);
            ctx->uthreads--;
#endif

            return nrets;

        case NGX_HTTP_LUA_CO_DEAD:
            dd("uthread already waited: %p (parent %p)", sub_coctx,
               coctx);

found_dead:
            if (i < nargs) {
                /* just ignore it if it is not the last one */
                continue;
            }

            /* being the last one */
            lua_pushnil(L);
            lua_pushliteral(L, "already waited");
            return 2;

        default:
            dd("uthread %p still alive, status: %d, parent %p", sub_coctx,
               sub_coctx->co_status, coctx);
            break;
        }

        ngx_http_lua_probe_user_thread_wait(L, sub_coctx->co);
        sub_coctx->waited_by_parent = 1;
    }

    return lua_yield(L, 0);
}
int
ngx_http_lua_coroutine_create_helper(lua_State *L, ngx_http_request_t *r,
    ngx_http_lua_ctx_t *ctx, ngx_http_lua_co_ctx_t **pcoctx)
{
    lua_State                     *vm;  /* the Lua VM */
    lua_State                     *co;  /* new coroutine to be created */
    ngx_http_lua_co_ctx_t         *coctx; /* co ctx for the new coroutine */

    luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), 1,
                  "Lua function expected");

    ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE
                               | NGX_HTTP_LUA_CONTEXT_ACCESS
                               | NGX_HTTP_LUA_CONTEXT_CONTENT
                               | NGX_HTTP_LUA_CONTEXT_TIMER
                               | NGX_HTTP_LUA_CONTEXT_SSL_CERT);

    vm = ngx_http_lua_get_lua_vm(r, ctx);

    /* create new coroutine on root Lua state, so it always yields
     * to main Lua thread
     */
    co = lua_newthread(vm);

    ngx_http_lua_probe_user_coroutine_create(r, L, co);

    coctx = ngx_http_lua_get_co_ctx(co, ctx);
    if (coctx == NULL) {
        coctx = ngx_http_lua_create_co_ctx(r, ctx);
        if (coctx == NULL) {
            return luaL_error(L, "no memory");
        }

    } else {
        ngx_memzero(coctx, sizeof(ngx_http_lua_co_ctx_t));
        coctx->co_ref = LUA_NOREF;
    }

    coctx->co = co;
    coctx->co_status = NGX_HTTP_LUA_CO_SUSPENDED;

    /* make new coroutine share globals of the parent coroutine.
     * NOTE: globals don't have to be separated! */
    ngx_http_lua_get_globals_table(L);
    lua_xmove(L, co, 1);
    ngx_http_lua_set_globals_table(co);

    lua_xmove(vm, L, 1);    /* move coroutine from main thread to L */

    lua_pushvalue(L, 1);    /* copy entry function to top of L*/
    lua_xmove(L, co, 1);    /* move entry function from L to co */

    if (pcoctx) {
        *pcoctx = coctx;
    }

#ifdef NGX_LUA_USE_ASSERT
    coctx->co_top = 1;
#endif

    return 1;    /* return new coroutine to Lua */
}
Пример #16
0
int ravaL_thread_once(rava_thread_t* self)
{
  if (!QUEUE_EMPTY(&self->rouse)) {
    QUEUE* q;
    rava_fiber_t* fiber;

    q = QUEUE_HEAD(&self->rouse);
    fiber = QUEUE_DATA(q, rava_fiber_t, queue);

    QUEUE_REMOVE(q);

    TRACE("[%p] rouse fiber: %p\n", self, fiber);

    if (fiber->flags & RAVA_STATE_DEAD) {
      TRACE("[%p] fiber is dead: %p\n", self, fiber);

      luaL_error(self->L, "cannot resume a dead fiber");
    } else {
      int stat, narg;
      narg = lua_gettop(fiber->L);

      if (!(fiber->flags & RAVA_STATE_START)) {
        /* first entry, ignore function arg */
        fiber->flags |= RAVA_STATE_START;

        --narg;
      }

      self->curr = (rava_state_t*)fiber;

      TRACE("[%p] calling lua_resume on: %p\n", self, fiber);

      stat = lua_resume(fiber->L, narg);

      TRACE("resume returned\n");

      self->curr = (rava_state_t*)self;

      switch (stat) {
        case LUA_YIELD:
          TRACE("[%p] seen LUA_YIELD\n", self);

          /* if called via coroutine.yield() then we're still in the queue */
          if (fiber->flags & RAVA_STATE_READY) {
            TRACE("%p is still ready, back in the queue\n", fiber);

            QUEUE_INSERT_TAIL(&self->rouse, &fiber->queue);
          }

          break;
        case 0: {
          /* normal exit, wake up joining states */
          int i, narg;

          narg = lua_gettop(fiber->L);

          TRACE("[%p] normal exit - fiber: %p, narg: %i\n", self, fiber, narg);

          QUEUE* q;
          rava_state_t* s;

          while (!QUEUE_EMPTY(&fiber->rouse)) {
            q = QUEUE_HEAD(&fiber->rouse);
            s = QUEUE_DATA(q, rava_state_t, join);

            QUEUE_REMOVE(q);

            TRACE("calling ravaL_state_ready(%p)\n", s);

            ravaL_state_ready(s);

            if (s->type == RAVA_STATE_TYPE_FIBER) {
              lua_checkstack(fiber->L, 1);
              lua_checkstack(s->L, narg);

              for (i = 1; i <= narg; i++) {
                lua_pushvalue(fiber->L, i);
                lua_xmove(fiber->L, s->L, 1);
              }
            }
          }

          TRACE("closing fiber %p\n", fiber);

          ravaL_fiber_close(fiber);

          break;
        }
        default:
          TRACE("ERROR: in fiber\n");

          lua_pushvalue(fiber->L, -1);  /* error message */
          lua_xmove(fiber->L, self->L, 1);
          ravaL_fiber_close(fiber);
          lua_error(self->L);
      }
    }
  }

  return !QUEUE_EMPTY(&self->rouse);
}
Пример #17
0
static int l_load_music_async_callback(lua_State *L)
{
    load_music_async_t *async = (load_music_async_t*)lua_touserdata(L, 1);

    // Replace light UD with full UD
    lua_pushvalue(L, 1);
    lua_gettable(L, LUA_REGISTRYINDEX);
    lua_insert(L, 1);
    lua_pushnil(L);
    lua_settable(L, LUA_REGISTRYINDEX);

    // Get CB state and function
    lua_pushvalue(L, 1);
    lua_gettable(L, LUA_REGISTRYINDEX);
    lua_rawgeti(L, -1, 1);
    lua_State *cbL = lua_tothread(L, -1);
    // NB: cbL may equal L, or it may not
    lua_pop(L, 1);
    lua_rawgeti(L, -1, 2);
    if(L != cbL)
        lua_xmove(L, cbL, 1);

    // Push CB arg
    int nargs = 1;
    if(async->music == NULL)
    {
        lua_pushnil(cbL);
        if(async->err)
        {
            if(*async->err)
            {
                lua_pushstring(cbL, async->err);
                nargs = 2;
            }
            free(async->err);
        }
    }
    else
    {
        lua_rawgeti(L, 2, 3);
        if(L != cbL)
            lua_xmove(L, cbL, 1);
        music_t* pLMusic = (music_t*)lua_touserdata(cbL, -1);
        pLMusic->pMusic = async->music;
        pLMusic->pRWop = async->rwop;
        async->music = NULL;
        async->rwop = NULL;
    }

    // Finish cleanup
    if(async->rwop)
        SDL_FreeRW(async->rwop);
    lua_pushvalue(L, 1);
    lua_pushnil(L);
    lua_settable(L, LUA_REGISTRYINDEX);

    // Callback
    if(cbL == L)
    {
        lua_call(cbL, nargs, 0);
        return 0;
    }
    if(lua_pcall(cbL, nargs, 0, 0) != 0)
    {
        lua_pushliteral(L, "Error in async music load callback: ");
        lua_xmove(cbL, L, 1);
        lua_tostring(L, -1);
        lua_concat(L, 2);
        lua_error(L);
    }
    return 0;
}
Пример #18
0
static int l_mainloop(lua_State *L)
{
    luaL_checktype(L, 1, LUA_TTHREAD);
    lua_State *dispatcher = lua_tothread(L, 1);

    fps_ctrl *fps_control = (fps_ctrl*)lua_touserdata(L, luaT_upvalueindex(1));
    SDL_TimerID timer = SDL_AddTimer(30, timer_frame_callback, NULL);
    SDL_Event e;

    while(SDL_WaitEvent(&e) != 0)
    {
        bool do_frame = false;
        bool do_timer = false;
        do
        {
            int nargs;
            switch(e.type)
            {
            case SDL_QUIT:
                goto leave_loop;
            case SDL_KEYDOWN:
                lua_pushliteral(dispatcher, "keydown");
                lua_pushstring(dispatcher, SDL_GetKeyName(e.key.keysym.sym));
                l_push_modifiers_table(dispatcher, e.key.keysym.mod);
                lua_pushboolean(dispatcher, e.key.repeat != 0);
                nargs = 4;
                break;
            case SDL_KEYUP:
                lua_pushliteral(dispatcher, "keyup");
                lua_pushstring(dispatcher, SDL_GetKeyName(e.key.keysym.sym));
                nargs = 2;
                break;
            case SDL_TEXTINPUT:
                lua_pushliteral(dispatcher, "textinput");
                lua_pushstring(dispatcher, e.text.text);
                nargs = 2;
                break;
            case SDL_TEXTEDITING:
                lua_pushliteral(dispatcher, "textediting");
                lua_pushstring(dispatcher, e.edit.text);
                lua_pushinteger(dispatcher, e.edit.start);
                lua_pushinteger(dispatcher, e.edit.length);
                nargs = 4;
                break;
            case SDL_MOUSEBUTTONDOWN:
                lua_pushliteral(dispatcher, "buttondown");
                lua_pushinteger(dispatcher, e.button.button);
                lua_pushinteger(dispatcher, e.button.x);
                lua_pushinteger(dispatcher, e.button.y);
                nargs = 4;
                break;
            case SDL_MOUSEBUTTONUP:
                lua_pushliteral(dispatcher, "buttonup");
                lua_pushinteger(dispatcher, e.button.button);
                lua_pushinteger(dispatcher, e.button.x);
                lua_pushinteger(dispatcher, e.button.y);
                nargs = 4;
                break;
            case SDL_MOUSEWHEEL:
                lua_pushliteral(dispatcher, "mousewheel");
                lua_pushinteger(dispatcher, e.wheel.x);
                lua_pushinteger(dispatcher, e.wheel.y);
                nargs = 3;
                break;
            case SDL_MOUSEMOTION:
                lua_pushliteral(dispatcher, "motion");
                lua_pushinteger(dispatcher, e.motion.x);
                lua_pushinteger(dispatcher, e.motion.y);
                lua_pushinteger(dispatcher, e.motion.xrel);
                lua_pushinteger(dispatcher, e.motion.yrel);
                nargs = 5;
                break;
            case SDL_WINDOWEVENT:
                switch (e.window.event) {
                    case SDL_WINDOWEVENT_FOCUS_GAINED:
                        lua_pushliteral(dispatcher, "active");
                        lua_pushinteger(dispatcher, 1);
                        nargs = 2;
                        break;
                    case SDL_WINDOWEVENT_FOCUS_LOST:
                        lua_pushliteral(dispatcher, "active");
                        lua_pushinteger(dispatcher, 0);
                        nargs = 2;
                        break;
                    default:
                        nargs = 0;
                        break;
                }
                break;
            case SDL_USEREVENT_MUSIC_OVER:
                lua_pushliteral(dispatcher, "music_over");
                nargs = 1;
                break;
            case SDL_USEREVENT_CPCALL:
                if(luaT_cpcall(L, (lua_CFunction)e.user.data1, e.user.data2))
                {
                    SDL_RemoveTimer(timer);
                    lua_pushliteral(L, "callback");
                    return 2;
                }
                nargs = 0;
                break;
            case SDL_USEREVENT_TICK:
                do_timer = true;
                nargs = 0;
                break;
            case SDL_USEREVENT_MOVIE_OVER:
                lua_pushliteral(dispatcher, "movie_over");
                nargs = 1;
                break;
            case SDL_USEREVENT_SOUND_OVER:
                lua_pushliteral(dispatcher, "sound_over");
                lua_pushinteger(dispatcher, *(static_cast<int*>(e.user.data1)));
                nargs = 2;
                break;
            default:
                nargs = 0;
                break;
            }
            if(nargs != 0)
            {
                if(luaT_resume(dispatcher, dispatcher, nargs) != LUA_YIELD)
                {
                    goto leave_loop;
                }
                do_frame = do_frame || (lua_toboolean(dispatcher, 1) != 0);
                lua_settop(dispatcher, 0);
            }
        } while(SDL_PollEvent(&e) != 0);
        if(do_timer)
        {
            lua_pushliteral(dispatcher, "timer");
            if(luaT_resume(dispatcher, dispatcher, 1) != LUA_YIELD)
            {
                break;
            }
            do_frame = do_frame || (lua_toboolean(dispatcher, 1) != 0);
            lua_settop(dispatcher, 0);
        }
        if(do_frame || !fps_control->limit_fps)
        {
            do
            {
                if(fps_control->track_fps)
                {
                    fps_control->count_frame();
                }
                lua_pushliteral(dispatcher, "frame");
                if(luaT_resume(dispatcher, dispatcher, 1) != LUA_YIELD)
                {
                    goto leave_loop;
                }
                lua_settop(dispatcher, 0);
            } while(fps_control->limit_fps == false && SDL_PollEvent(NULL) == 0);
        }

        // No events pending - a good time to do a bit of garbage collection
        lua_gc(L, LUA_GCSTEP, 2);
    }

leave_loop:
    SDL_RemoveTimer(timer);
    int n = lua_gettop(dispatcher);
    if(lua_status(dispatcher) >= LUA_ERRRUN)
    {
        n = 1;
    }
    lua_checkstack(L, n);
    lua_xmove(dispatcher, L, n);
    return n;
}
static ngx_int_t
ngx_http_lua_rewrite_by_chunk(lua_State *L, ngx_http_request_t *r)
{
    int                      co_ref;
    lua_State               *co;
    ngx_int_t                rc;
    ngx_connection_t        *c;
    ngx_http_lua_ctx_t      *ctx;
    ngx_http_cleanup_t      *cln;

    ngx_http_lua_loc_conf_t     *llcf;

    /*  {{{ new coroutine to handle request */
    co = ngx_http_lua_new_thread(r, L, &co_ref);

    if (co == NULL) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "lua: failed to create new coroutine to handle request");

        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    /*  move code closure to new coroutine */
    lua_xmove(L, co, 1);

    /*  set closure's env table to new coroutine's globals table */
    ngx_http_lua_get_globals_table(co);
    lua_setfenv(co, -2);

    /*  save nginx request in coroutine globals table */
    ngx_http_lua_set_req(co, r);

    /*  {{{ initialize request context */
    ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);

    dd("ctx = %p", ctx);

    if (ctx == NULL) {
        return NGX_ERROR;
    }

    ngx_http_lua_reset_ctx(r, L, ctx);

    ctx->entered_rewrite_phase = 1;

    ctx->cur_co_ctx = &ctx->entry_co_ctx;
    ctx->cur_co_ctx->co = co;
    ctx->cur_co_ctx->co_ref = co_ref;
#ifdef NGX_LUA_USE_ASSERT
    ctx->cur_co_ctx->co_top = 1;
#endif

    /*  }}} */

    /*  {{{ register request cleanup hooks */
    if (ctx->cleanup == NULL) {
        cln = ngx_http_cleanup_add(r, 0);
        if (cln == NULL) {
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

        cln->handler = ngx_http_lua_request_cleanup_handler;
        cln->data = ctx;
        ctx->cleanup = &cln->handler;
    }
    /*  }}} */

    ctx->context = NGX_HTTP_LUA_CONTEXT_REWRITE;

    llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);

    if (llcf->check_client_abort) {
        r->read_event_handler = ngx_http_lua_rd_check_broken_connection;

    } else {
        r->read_event_handler = ngx_http_block_reading;
    }

    rc = ngx_http_lua_run_thread(L, r, ctx, 0);

    if (rc == NGX_ERROR || rc > NGX_OK) {
        return rc;
    }

    c = r->connection;

    if (rc == NGX_AGAIN) {
        rc = ngx_http_lua_run_posted_threads(c, L, r, ctx);

    } else if (rc == NGX_DONE) {
        ngx_http_lua_finalize_request(r, NGX_DONE);
        rc = ngx_http_lua_run_posted_threads(c, L, r, ctx);
    }

    if (rc == NGX_OK || rc == NGX_DECLINED) {
        if (r->header_sent) {
            dd("header already sent");

            /* response header was already generated in access_by_lua*,
             * so it is no longer safe to proceed to later phases
             * which may generate responses again */

            if (!ctx->eof) {
                dd("eof not yet sent");

                rc = ngx_http_lua_send_chain_link(r, ctx, NULL
                                                  /* indicate last_buf */);
                if (rc == NGX_ERROR || rc > NGX_OK) {
                    return rc;
                }
            }

            return NGX_HTTP_OK;
        }

        return NGX_DECLINED;
    }

    return rc;
}
Пример #20
0
/*
 * Arguments: evq_udata, [timeout (milliseconds), once (boolean),
 *	fetch (boolean)]
 * Returns: [evq_udata | timeout (false)]
 *	|
 * Returns: [ev_ludata, obj_udata, event (string: "r", "w", "t", "e"),
 *	eof_status (number)]
 */
static int
levq_loop (lua_State *L)
{
    struct event_queue *evq = checkudata(L, 1, EVQ_TYPENAME);
    const msec_t timeout = (lua_type(L, 2) != LUA_TNUMBER)
     ? TIMEOUT_INFINITE : (msec_t) lua_tointeger(L, 2);
    const int once = lua_toboolean(L, 3);
    const int fetch = lua_toboolean(L, 4);

#undef ARG_LAST
#define ARG_LAST	1

    lua_settop(L, ARG_LAST);
    {
	lua_State *NL = evq->L;

	lua_pushvalue(NL, EVQ_CORO_CALLBACK);
	lua_pushvalue(NL, EVQ_CORO_UDATA);
	lua_xmove(NL, L, 2);
    }

#ifdef EVQ_POST_INIT
    if (evq->ev_post) {
	evq_post_init(evq->ev_post);
	evq->ev_post = NULL;
    }
#endif

    while (!evq_is_empty(evq)) {
	struct event *ev;

	if (evq->stop) {
	    evq->stop = 0;
	    break;
	}

	/* process synchronous operations */
	if (evq->sync_op) {
	    struct evq_sync_op *op = evq->sync_op;

	    evq->sync_op = NULL;
	    levq_sync_process(L, evq, op);
	}

	if (!evq->ev_ready) {
	    const int res = evq_wait(evq, timeout);

	    if (res == EVQ_TIMEOUT) {
		lua_pushboolean(L, 0);
		return 1;
	    }
	    if (res == EVQ_FAILED)
		return sys_seterror(L, 0);
	}

	ev = evq->ev_ready;
	if (!ev) continue;
	do {
	    const unsigned int ev_flags = ev->flags;

	    /* clear EVENT_ACTIVE and EVENT_*_RES flags */
	    ev->flags &= EVENT_MASK;
	    evq->ev_ready = ev->next_ready;

	    if (ev_flags & EVENT_DELETE) {
		/* postponed deletion of active event */
		levq_del_event(evq, ev);
	    } else {
		if ((ev_flags & EVENT_CALLBACK) || fetch) {
		    const int ev_id = ev->ev_id;

		    /* callback function */
		    lua_rawgeti(L, ARG_LAST+1, ev_id);
		    /* arguments */
		    if (!(ev_flags & EVENT_CALLBACK_SCHED)) {
			lua_pushvalue(L, 1);  /* evq_udata */
			lua_pushlightuserdata(L, ev);  /* ev_ludata */
			lua_rawgeti(L, ARG_LAST+2, ev_id);  /* obj_udata */
		    }
		    if (ev_flags & EVENT_EOF_MASK_RES) {
			lua_pushliteral(L, "e");
			lua_pushinteger(L,
			 (int) ev_flags >> EVENT_EOF_SHIFT_RES);
		    } else {
			lua_pushstring(L,
			 (ev_flags & EVENT_TIMEOUT_RES) ? "t"
			 : (ev_flags & EVENT_WRITE_RES) ? "w" : "r");
			lua_pushnil(L);
		    }
		}

		if ((ev_flags & EVENT_ONESHOT) && !event_deleted(ev))
		    evq_del(ev, 1);

		if (event_deleted(ev))
		    levq_del_event(evq, ev);  /* deletion of oneshot event */
#ifdef EVQ_POST_INIT
		else evq->ev_post = ev;
#endif

		if (ev_flags & EVENT_CALLBACK_SCHED) {
		    /* callback function: coroutine */
		    lua_State *co = lua_tothread(L, ARG_LAST+3);

		    lua_xmove(L, co, 2);
		    lua_pop(L, 1);  /* pop coroutine */

		    sys_sched_event_ready(co, ev);
		} else if (ev_flags & EVENT_CALLBACK_CORO) {
		    lua_State *co = lua_tothread(L, ARG_LAST+3);

		    lua_xmove(L, co, 5);
		    lua_pop(L, 1);  /* pop coroutine */

		    switch (lua_resume(co, L, 5)) {
		    case 0:
			lua_settop(co, 0);
			if (!event_deleted(ev)) {
			    evq_del(ev, 0);
			    levq_del_event(evq, ev);
#ifdef EVQ_POST_INIT
			    evq->ev_post = NULL;
#endif
			}
			break;
		    case LUA_YIELD:
			lua_settop(co, 0);
			break;
		    default:
			lua_xmove(co, L, 1);  /* error message */
			lua_error(L);
		    }
		} else if (ev_flags & EVENT_CALLBACK)
		    lua_call(L, 5, 0);
		else if (fetch)
		    return 4;

#ifdef EVQ_POST_INIT
		if (evq->ev_post) {
		    evq_post_init(evq->ev_post);
		    evq->ev_post = NULL;
		}
#endif
	    }
	    ev = evq->ev_ready;
	} while (ev);
static ngx_int_t
ngx_http_lua_rewrite_by_chunk(lua_State *L, ngx_http_request_t *r)
{
    int                      cc_ref;
    lua_State               *cc;
    ngx_http_lua_ctx_t      *ctx;
    ngx_http_cleanup_t      *cln;
    ngx_int_t                rc;

    /*  {{{ new coroutine to handle request */
    cc = ngx_http_lua_new_thread(r, L, &cc_ref);

    if (cc == NULL) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                "lua: failed to create new coroutine to handle request");

        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    /*  move code closure to new coroutine */
    lua_xmove(L, cc, 1);

    /*  set closure's env table to new coroutine's globals table */
    lua_pushvalue(cc, LUA_GLOBALSINDEX);
    lua_setfenv(cc, -2);

    /*  save reference of code to ease forcing stopping */
    lua_pushvalue(cc, -1);
    lua_setglobal(cc, GLOBALS_SYMBOL_RUNCODE);

    /*  save nginx request in coroutine globals table */
    lua_pushlightuserdata(cc, r);
    lua_setglobal(cc, GLOBALS_SYMBOL_REQUEST);
    /*  }}} */

    /*  {{{ initialize request context */
    ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);

    dd("ctx = %p", ctx);

    if (ctx == NULL) {
        return NGX_ERROR;
    }

    ngx_http_lua_reset_ctx(r, L, ctx);

    ctx->entered_rewrite_phase = 1;

    ctx->cc = cc;
    ctx->cc_ref = cc_ref;

    /*  }}} */

    /*  {{{ register request cleanup hooks */
    if (ctx->cleanup == NULL) {
        cln = ngx_http_cleanup_add(r, 0);
        if (cln == NULL) {
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

        cln->handler = ngx_http_lua_request_cleanup;
        cln->data = r;
        ctx->cleanup = &cln->handler;
    }
    /*  }}} */

    rc = ngx_http_lua_run_thread(L, r, ctx, 0);

    if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) {
        return rc;
    }

    if (rc == NGX_AGAIN) {
        return NGX_DONE;
    }

    if (rc == NGX_DONE) {
        ngx_http_finalize_request(r, NGX_DONE);
        return NGX_DONE;
    }

    if (rc >= NGX_HTTP_OK && rc < NGX_HTTP_SPECIAL_RESPONSE) {
        return rc;
    }

    return NGX_DECLINED;
}
ngx_int_t
ngx_http_lua_content_by_chunk(lua_State *L, ngx_http_request_t *r)
{
    int                      co_ref;
    ngx_int_t                rc;
    lua_State               *co;
    ngx_http_lua_ctx_t      *ctx;
    ngx_http_cleanup_t      *cln;

    ngx_http_lua_loc_conf_t      *llcf;

    dd("content by chunk");

    ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);

    if (ctx == NULL) {
        ctx = ngx_http_lua_create_ctx(r);
        if (ctx == NULL) {
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

    } else {
        dd("reset ctx");
        ngx_http_lua_reset_ctx(r, L, ctx);
    }

    ctx->entered_content_phase = 1;

    /*  {{{ new coroutine to handle request */
    co = ngx_http_lua_new_thread(r, L, &co_ref);

    if (co == NULL) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                     "lua: failed to create new coroutine to handle request");

        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    /*  move code closure to new coroutine */
    lua_xmove(L, co, 1);

    /*  set closure's env table to new coroutine's globals table */
    ngx_http_lua_get_globals_table(co);
    lua_setfenv(co, -2);

    /*  save nginx request in coroutine globals table */
    ngx_http_lua_set_req(co, r);

    ctx->cur_co_ctx = &ctx->entry_co_ctx;
    ctx->cur_co_ctx->co = co;
    ctx->cur_co_ctx->co_ref = co_ref;
#ifdef ngx_http_lua_assert
    ctx->cur_co_ctx->co_top = 1;
#endif

    /*  {{{ register request cleanup hooks */
    if (ctx->cleanup == NULL) {
        cln = ngx_http_cleanup_add(r, 0);
        if (cln == NULL) {
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

        cln->handler = ngx_http_lua_request_cleanup_handler;
        cln->data = ctx;
        ctx->cleanup = &cln->handler;
    }
    /*  }}} */

    ctx->context = NGX_HTTP_LUA_CONTEXT_CONTENT;

    llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);

    if (llcf->check_client_abort) {
        r->read_event_handler = ngx_http_lua_rd_check_broken_connection;

    } else {
        r->read_event_handler = ngx_http_block_reading;
    }

    rc = ngx_http_lua_run_thread(L, r, ctx, 0);

    if (rc == NGX_ERROR || rc >= NGX_OK) {
        return rc;
    }

    if (rc == NGX_AGAIN) {
        return ngx_http_lua_content_run_posted_threads(L, r, ctx, 0);
    }

    if (rc == NGX_DONE) {
        return ngx_http_lua_content_run_posted_threads(L, r, ctx, 1);
    }

    return NGX_OK;
}
int
ngx_http_lua_coroutine_create_helper(lua_State *L, ngx_http_request_t **pr,
    ngx_http_lua_ctx_t **pctx, ngx_http_lua_co_ctx_t **pcoctx)
{
    lua_State                     *mt;  /* the main thread */
    lua_State                     *co;  /* new coroutine to be created */
    ngx_http_request_t            *r;
    ngx_http_lua_main_conf_t      *lmcf;
    ngx_http_lua_ctx_t            *ctx;
    ngx_http_lua_co_ctx_t         *coctx; /* co ctx for the new coroutine */

    luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), 1,
                 "Lua function expected");

    lua_pushlightuserdata(L, &ngx_http_lua_request_key);
    lua_rawget(L, LUA_GLOBALSINDEX);
    r = lua_touserdata(L, -1);
    lua_pop(L, 1);

    if (r == NULL) {
        return luaL_error(L, "no request found");
    }

    ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
    if (ctx == NULL) {
        return luaL_error(L, "no request ctx found");
    }

    ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE
                               | NGX_HTTP_LUA_CONTEXT_ACCESS
                               | NGX_HTTP_LUA_CONTEXT_CONTENT);

    lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module);
    mt = lmcf->lua;

    /* create new coroutine on root Lua state, so it always yields
     * to main Lua thread
     */
    co = lua_newthread(mt);

    ngx_http_lua_probe_user_coroutine_create(r, L, co);

    coctx = ngx_http_lua_create_co_ctx(r, ctx);
    if (coctx == NULL) {
        return luaL_error(L, "out of memory");
    }

    coctx->co = co;
    coctx->co_status = NGX_HTTP_LUA_CO_SUSPENDED;

    /* make new coroutine share globals of the parent coroutine.
     * NOTE: globals don't have to be separated! */
    lua_pushvalue(L, LUA_GLOBALSINDEX);
    lua_xmove(L, co, 1);
    lua_replace(co, LUA_GLOBALSINDEX);

    lua_xmove(mt, L, 1);    /* move coroutine from main thread to L */

    lua_pushvalue(L, 1);    /* copy entry function to top of L*/
    lua_xmove(L, co, 1);    /* move entry function from L to co */

    if (pcoctx) {
        *pcoctx = coctx;
    }

    if (pctx) {
        *pctx = ctx;
    }

    if (pr) {
        *pr = r;
    }

    return 1;    /* return new coroutine to Lua */
}
Пример #24
0
static int
ngx_http_lua_uthread_wait(lua_State *L)
{
    int                          i, nargs, nrets;
    lua_State                   *sub_co;
    ngx_http_request_t          *r;
    ngx_http_lua_ctx_t          *ctx;
    ngx_http_lua_co_ctx_t       *coctx, *sub_coctx;

    lua_pushlightuserdata(L, &ngx_http_lua_request_key);
    lua_rawget(L, LUA_GLOBALSINDEX);
    r = lua_touserdata(L, -1);
    lua_pop(L, 1);

    if (r == NULL) {
        return luaL_error(L, "no request found");
    }

    ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
    if (ctx == NULL) {
        return luaL_error(L, "no request ctx found");
    }

    ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE
                               | NGX_HTTP_LUA_CONTEXT_ACCESS
                               | NGX_HTTP_LUA_CONTEXT_CONTENT);

    coctx = ctx->cur_co_ctx;

    nargs = lua_gettop(L);

    for (i = 1; i <= nargs; i++) {
        sub_co = lua_tothread(L, i);

        luaL_argcheck(L, sub_co, i, "lua thread expected");

        sub_coctx = ngx_http_lua_get_co_ctx(sub_co, ctx);
        if (sub_coctx == NULL) {
            return luaL_error(L, "no co ctx found for the ngx.thread "
                              "instance given");
        }

        if (!sub_coctx->is_uthread) {
            return luaL_error(L, "attempt to wait on a coroutine that is "
                              "not a user thread");
        }

        if (sub_coctx->parent_co_ctx != coctx) {
            return luaL_error(L, "only the parent coroutine can wait on the "
                              "thread");
        }

        switch (sub_coctx->co_status) {
        case NGX_HTTP_LUA_CO_ZOMBIE:

            ngx_http_lua_probe_info("found zombie child");

            nrets = lua_gettop(sub_coctx->co);

            dd("child retval count: %d, %s: %s", n,
                    luaL_typename(sub_coctx->co, -1),
                    lua_tostring(sub_coctx->co, -1));

            if (nrets) {
                lua_xmove(sub_coctx->co, L, nrets);
            }

#if 1
            ngx_http_lua_del_thread(r, L, ctx, sub_coctx);
            ctx->uthreads--;
#endif

            return nrets;

        default:
            /* still alive */
            break;
        }

        sub_coctx->waited_by_parent = 1;
    }

    return lua_yield(L, 0);
}
Пример #25
0
bool EmbeddedGamePanel::loadLua()
{
    // Create state
    m_L = luaL_newstate();
    lua_atpanic(m_L, _l_panic);

    // Save a pointer to ourselves in the registry
    lua_pushliteral(m_L, "wxWindow");
    lua_pushlightuserdata(m_L, reinterpret_cast<wxWindow*>(this));
    lua_settable(m_L, LUA_REGISTRYINDEX);

    // Open default libraries, and override appropriate bits
    luaL_openlibs(m_L);
    luaT_execute(m_L, "print = ...", _l_print);

    // Set _MAP_EDITOR to true, to allow scripts to notice that they are
    // running inside this component, rather than standalone.
    luaT_execute(m_L, "_MAP_EDITOR = true");

    // Load CorsixTH.lua and perform other initialisation needed by it
    lua_settop(m_L, 0);
    lua_pushcfunction(m_L, CorsixTH_lua_stacktrace);
    lua_pushcfunction(m_L, CorsixTH_lua_main_no_eval);
    lua_checkstack(m_L, wxTheApp->argc);
    for(int i = 0; i < wxTheApp->argc; ++ i)
        lua_pushstring(m_L, wxTheApp->argv[i]);
    if(lua_pcall(m_L, wxTheApp->argc, 1, 1))
    {
        if(m_pPrintTarget)
        {
            m_pPrintTarget->AppendText(L"Error initialising Lua: ");
            m_pPrintTarget->AppendText(lua_tostring(m_L, -1));
            m_pPrintTarget->AppendText(L"\n");
        }
        return false;
    }
    // NB: CorsixTH_lua_main_no_eval will have loaded CorsixTH.lua and left it
    // as the top value on the stack, but will not have executed it.
    // The stack will hence have two things on it: the stacktrace function,
    // and the loaded CorsixTH.lua

    // Overwrite what CorsixTH_lua_main_no_eval registered for require("sdl")
    // with our own function that uses wxWidgets to do what SDL would have.
    luaT_execute(m_L, "package.preload.sdl = ...", _l_open_sdl);

    // Replace the Surface:endFrame() function with our own
    lua_getglobal(m_L, "require");
    lua_pushliteral(m_L, "TH");
    lua_call(m_L, 1, 1);
    lua_getfield(m_L, -1, "surface");
    lua_getfield(m_L, -1, "endFrame");
    lua_pushcclosure(m_L, _l_end_frame, 1);
    lua_setfield(m_L, -2, "endFrame");
    lua_pop(m_L, 2);

    // Perform extra initialisation
    if(m_fnExtraLuaInit)
    {
        if(lua_cpcall(m_L, m_fnExtraLuaInit, m_pExtraLuaInitArg) != 0)
            lua_pop(m_L, 1);
    }

    // Execute CorsixTH.lua in a coroutine
    lua_getglobal(m_L, "coroutine");
    lua_getfield(m_L, -1, "create");
    lua_replace(m_L, -2);
    lua_insert(m_L, -2);
    lua_call(m_L, 1, 1);
    lua_State *L = lua_tothread(m_L, -1);
    if(lua_resume(L, 0) != LUA_YIELD)
    {
        if(m_pPrintTarget)
        {
            // Push debug.traceback onto m_L
            lua_getglobal(m_L, "debug");
            lua_getfield(m_L, -1, "traceback");
            lua_replace(m_L, -2);
            // Push the thread onto m_L
            lua_pushvalue(m_L, -2);
            // Push tostring(errmsg) onto m_L
            lua_getglobal(m_L, "tostring");
            lua_xmove(L, m_L, 1);
            lua_call(m_L, 1, 1);
            // Push constant 1 onto m_L
            lua_pushinteger(m_L, 1);
            // Call debug.traceback(thread, tostring(err), 1)
            lua_call(m_L, 3, 1);
            // Display resulting string and pop it
            m_pPrintTarget->AppendText(L"Error initialising Lua: ");
            m_pPrintTarget->AppendText(lua_tostring(m_L, -1));
            m_pPrintTarget->AppendText(L"\n");
            lua_pop(m_L, 1);
        }
        return false;
    }
    lua_settop(L, 1);
    m_Lthread = L;

    // The stack of the Lua states is now as follows:
    // m_L: stacktrace function, m_Lthread <top
    // m_Lthread: event dispatch coroutine <top

    return true;
}