diff --git a/config.h.guess b/config.h.guess index 1727a7a..e6405ba 100644 --- a/config.h.guess +++ b/config.h.guess @@ -853,5 +853,33 @@ #define STRERROR_R_CHAR_P ((AG_GLIBC_PREREQ(0,0) || AG_UCLIBC_PREREQ(0,0,0)) && (HAVE__GNU_SOURCE || !(_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600))) #endif +#ifndef HAVE_GLIBC_PTHREAD +#define HAVE_GLIBC_PTHREAD (AG_GLIBC_PREREQ(2,12) && __linux__) +#endif + +#ifndef HAVE_NETBSD_PTHREAD +/*5.0.0 has setname() but no getname(). let's not support it for now.*/ +#define HAVE_NETBSD_PTHREAD (AG_NETBSD_PREREQ(6,0,0)) +#endif + +#ifndef HAVE_FREEBSD_PTHREAD +#define HAVE_FREEBSD_PTHREAD (AG_FREEBSD_PREREQ(5,2,1)) +#endif + +#ifndef HAVE_OPENBSD_PTHREAD +#define HAVE_OPENBSD_PTHREAD (AG_OPENBSD_PREREQ(3,6)) +#endif + +#ifndef HAVE_MACOSX_PTHREAD +#define HAVE_MACOSX_PTHREAD (AG_MACOS_PREREQ(10,7,0)) +#endif + +#ifndef HAVE_PTHREAD_SETNAME +#define HAVE_PTHREAD_SETNAME (HAVE_GLIBC_PTHREAD || HAVE_NETBSD_PTHREAD || HAVE_FREEBSD_PTHREAD || HAVE_OPENBSD_PTHREAD || HAVE_MACOSX_PTHREAD) +#endif + +#ifndef HAVE_PTHREAD_GETNAME +#define HAVE_PTHREAD_GETNAME (HAVE_GLIBC_PTHREAD || HAVE_NETBSD_PTHREAD || HAVE_MACOSX_PTHREAD) +#endif #endif /* CONFIG_H_GUESS */ diff --git a/doc/cqueues.tex b/doc/cqueues.tex index 266b13b..f5efa39 100644 --- a/doc/cqueues.tex +++ b/doc/cqueues.tex @@ -803,6 +803,16 @@ \subsubsection{\fn{signal[]}} Returns a boolean and error value. If false, error value is an error code describing a local error, usually \errno{EAGAIN} or \errno{ETIMEDOUT}. If true, error value is 1) an error code describing a system error which the thread encountered, 2) an error message string returned by the new Lua instance, or 3) nil if completed successfully. +\subsubsection[\fn{thread:setname}]{\fn{thread:setname(name)}} +Set a name for the thread. The name must be a string not exceeding 15 characters in length. Supported on Linux, FreeBSD, NetBSD, OpenBSD. \& Mac OS X. On OS X this function only works from inside the thread. + +Returns true on success, false, an error string, an error string and the errno if the name is too long or if the platform does not support this function. + +\subsubsection[\fn{thread:getname}]{\fn{thread:getname(name)}} +Get the name of the thread. Supported on Linux, NetBSD \& Mac OS X. + +Returns the name string, or nil, an error string and the errno if the platform does not support this function. + \end{Module} \begin{Module}{cqueues.notify} diff --git a/src/thread.c b/src/thread.c index 65d7fb8..b124e71 100644 --- a/src/thread.c +++ b/src/thread.c @@ -36,6 +36,9 @@ #include #include +#if (HAVE_OPENBSD_PTHREAD || HAVE_FREEBSD_PTHREAD) +#include +#endif #include @@ -755,6 +758,97 @@ static int ct_timeout(lua_State *L) { return 0; } /* ct_timeout() */ +#if HAVE_PTHREAD_SETNAME +static int ct_setname(lua_State *L) { + struct cthread *ct = ct_checkthread(L, 1); + char *name = luaL_checkstring(L, 2); + int rc; +#if HAVE_GLIBC_PTHREAD + rc = pthread_setname_np(ct->id, name); +#elif HAVE_NETBSD_PTHREAD + rc = pthread_setname_np(ct->id, "%s", name); +#elif (HAVE_FREEBSD_PTHREAD || HAVE_OPENBSD_PTHREAD) + rc = 0; + /* from FreeBSD & OpenBSD man page: + Because of the debugging nature of this function, all errors that may + appear inside are silently ignored. + */ + pthread_set_name_np(ct->id, name); +#elif HAVE_MACOSX_PTHREAD + if (pthread_equal(ct->id, pthread_self())) { + lua_pushboolean(L, 0); + lua_pushliteral(L, "thread name cannot be set from outside the thread on this platform"); + lua_pushinteger(L, EPERM); + return 3; + } + rc = pthread_setname_np(name); +#endif + switch(rc) { + case 0: + lua_pushboolean(L, 1); + return 1; + case ERANGE: + lua_pushboolean(L, 0); + lua_pushliteral(L, "thread name too long"); + lua_pushinteger(L, rc); + return 3; + case EINVAL: + lua_pushboolean(L, 0); + lua_pushliteral(L, "invalid parameter when setting thread name"); + lua_pushinteger(L, rc); + return 3; + case ENOMEM: + lua_pushboolean(L, 0); + lua_pushliteral(L, "out of memory when setting thread name"); + lua_pushinteger(L, rc); + return 3; + } +} /* ct_setname() */ +#else +static int ct_setname(lua_State *L) { + lua_pushnil(L); + lua_pushliteral(L, "setname() not supported on this platform"); + lua_pushinteger(L, EPERM); + return 3; +} /* ct_setname() */ +#endif + + +#if HAVE_PTHREAD_GETNAME +static int ct_getname(lua_State *L) { + struct cthread *ct = ct_checkthread(L, 1); + char buf[128]; + int rc = EINVAL; + /*all the pthread_getname_np interfaces are the same where supported*/ + rc = pthread_getname_np(ct->id, buf, 128); + switch(rc) { + case ERANGE: + lua_pushnil(L); + lua_pushliteral(L, "thread name too long"); + lua_pushinteger(L, rc); + return 3; + case EINVAL: + lua_pushnil(L); + lua_pushliteral(L, "invalid parameter when getting thread name"); + lua_pushinteger(L, rc); + return 3; + case ENOMEM: + lua_pushnil(L); + lua_pushliteral(L, "out of memory when getting thread name"); + lua_pushinteger(L, rc); + return 3; + } + lua_pushstring(L, buf); + return 1; +} /* ct_getname() */ +#else +static int ct_getname(lua_State *L) { + lua_pushnil(L); + lua_pushliteral(L, "getname() not supported on this platform"); + lua_pushinteger(L, EPERM); + return 3; +} /* ct_getname() */ +#endif static int ct__eq(lua_State *L) { struct cthread **a = luaL_testudata(L, 1, CQS_THREAD); @@ -804,6 +898,8 @@ static const luaL_Reg ct_methods[] = { { "pollfd", &ct_pollfd }, { "events", &ct_events }, { "timeout", &ct_timeout }, + { "setname", &ct_setname }, + { "getname", &ct_getname }, { NULL, NULL } };