Threads now take a label which can be displayed via system tools (e.g. top, ps).

This commit is contained in:
kevin 2024-02-18 08:37:33 -05:00
parent 24e35872b2
commit 64df75d9aa
19 changed files with 62 additions and 35 deletions

View File

@ -1368,7 +1368,7 @@ cw::rc_t cw::audio::device::alsa::create( handle_t& hRef, struct driver_str*& dr
p->pollfds = mem::allocZ<struct pollfd>( p->pollfdsAllocCnt );
p->pollfdsDesc = mem::allocZ<pollfdsDesc_t>(p->pollfdsAllocCnt );
if((rc = thread::create(p->thH,_threadFunc,p)) != kOkRC )
if((rc = thread::create(p->thH,_threadFunc,p,"alsa_audio")) != kOkRC )
{
rc = cwLogError(rc,"Thread create failed.");
}

View File

@ -664,7 +664,7 @@ cw::rc_t cw::audio::device::file::create( handle_t& hRef, struct driver_str*&
p->driver.deviceSeek = deviceSeek;
p->driver.deviceRealTimeReport = deviceRealTimeReport;
if((rc = create( p->threadH, _threadCbFunc, p )) != kOkRC )
if((rc = create( p->threadH, _threadCbFunc, p, "audio_dev_test" )) != kOkRC )
{
rc = cwLogError(rc,"Audio device file thread create failed.");
goto errLabel;

View File

@ -412,7 +412,7 @@ int main( int argc, const char* argv[] )
// create the TCP listening thread
if((rc = thread::create( app.tcpThreadH, tcpReceiveCallback, &app )) != kOkRC )
if((rc = thread::create( app.tcpThreadH, tcpReceiveCallback, &app, "avahi_suf" )) != kOkRC )
goto errLabel;
// Allocate Avahi thread

View File

@ -942,7 +942,7 @@ namespace cw
return cwLogError(rc,"Unable to create EuCon server.");
// Create the application thread
if((rc = thread::create( app.thH, appThreadFunc, &app )) != kOkRC )
if((rc = thread::create( app.thH, appThreadFunc, &app, "eu_con" )) != kOkRC )
return cwLogError(rc,"App thread create failed.");
// Start the application thread

View File

@ -371,7 +371,7 @@ namespace cw
time::get(t->nextTime);
if((rc = thread_mach::add(p->threadMachH,_timerThreadCb,t)) != kOkRC )
if((rc = thread_mach::add(p->threadMachH,_timerThreadCb,t, label)) != kOkRC )
{
rc = cwLogError(rc,"Timer thread assignment failed.");
}
@ -848,7 +848,7 @@ namespace cw
// create the socket thread
if( p->sockN > 0 )
if((rc = thread_mach::add(p->threadMachH,_socketThreadFunc,p)) != kOkRC )
if((rc = thread_mach::add(p->threadMachH,_socketThreadFunc,p,"io_socket")) != kOkRC )
{
rc = cwLogError(rc,"Error creating socket thread.");
goto errLabel;
@ -1567,7 +1567,7 @@ namespace cw
}
// create the audio group thread
if((rc = thread_mach::add(p->threadMachH,_audioGroupThreadFunc,p->audioGroupA+i)) != kOkRC )
if((rc = thread_mach::add(p->threadMachH,_audioGroupThreadFunc,p->audioGroupA+i,"io_audio_group")) != kOkRC )
{
rc = cwLogError(rc,"Error creating audio group thread.");
goto errLabel;
@ -2462,7 +2462,7 @@ void cw::io::realTimeReport( handle_t h )
// Thread
//
cw::rc_t cw::io::threadCreate( handle_t h, unsigned id, bool asyncFl, void* arg )
cw::rc_t cw::io::threadCreate( handle_t h, unsigned id, bool asyncFl, void* arg, const char* label )
{
rc_t rc = kOkRC;
io_t* p = _handleToPtr(h);
@ -2475,7 +2475,7 @@ cw::rc_t cw::io::threadCreate( handle_t h, unsigned id, bool asyncFl, void* arg
t->link = p->threadL;
p->threadL = t;
if((rc = thread_mach::add( p->threadMachH, _threadFunc, t )) != kOkRC )
if((rc = thread_mach::add( p->threadMachH, _threadFunc, t, label )) != kOkRC )
rc = cwLogError(rc,"Thread create failed.");
return rc;

2
cwIo.h
View File

@ -177,7 +177,7 @@ namespace cw
//
// Thread
//
rc_t threadCreate( handle_t h, unsigned id, bool asyncFl, void* arg );
rc_t threadCreate( handle_t h, unsigned id, bool asyncFl, void* arg, const char* label );
//----------------------------------------------------------------------------------------------------------
//

View File

@ -94,13 +94,13 @@ cw::rc_t cw::min_test( const object_t* cfg )
if((rc = create(app.ioH,cfg,minTestCb,&app)) != kOkRC )
return rc;
if((rc = threadCreate( app.ioH, kThread0Id, asyncFl, &app )) != kOkRC )
if((rc = threadCreate( app.ioH, kThread0Id, asyncFl, &app, "min_test_0" )) != kOkRC )
{
rc = cwLogError(rc,"Thread 0 create failed.");
goto errLabel;
}
if((rc = threadCreate( app.ioH, kThread1Id, asyncFl, &app )) != kOkRC )
if((rc = threadCreate( app.ioH, kThread1Id, asyncFl, &app, "min_test_1" )) != kOkRC )
{
rc = cwLogError(rc,"Thread 1 create failed.");
goto errLabel;

View File

@ -1317,7 +1317,7 @@ cw::rc_t cw::net::mdns::test()
}
// create the TCP listening thread
if((rc = thread::create( app.tcpThreadH, tcpReceiveCallback, &app )) != kOkRC )
if((rc = thread::create( app.tcpThreadH, tcpReceiveCallback, &app, "mdns" )) != kOkRC )
goto errLabel;

View File

@ -216,7 +216,8 @@ cw::rc_t cw::midi::device::create( handle_t& hRef,
if((rc = thread::create(p->threadH,
_thread_func,
p)) != kOkRC )
p,
"midi_dev")) != kOkRC )
{
rc = cwLogError(rc,"The MIDI file device thread create failed.");
goto errLabel;
@ -556,7 +557,7 @@ errLabel:
cw::rc_t cw::midi::device::start( handle_t h )
{
rc_t rc;
rc_t rc = kOkRC;
device_t* p = _handleToPtr(h);
if( p->fileDevStateId != kPlayingStateId )

View File

@ -365,7 +365,7 @@ cw::rc_t cw::nbmem::test_multi_threaded()
ctx.threadA[i].varA = mem::allocZ<void*>(threadVarN);
ctx.threadA[i].varN = threadVarN;
if((rc = thread::create(ctx.threadA[i].threadH, _test_thread_func, ctx.threadA + i )) != kOkRC )
if((rc = thread::create(ctx.threadA[i].threadH, _test_thread_func, ctx.threadA + i, "nb_mem" )) != kOkRC )
break;
}

View File

@ -92,7 +92,7 @@ cw::rc_t cw::serialPortSrv::create( handle_t& h, unsigned pollPeriodMs, unsigned
if((rc = serialPort::create( p->mgrH, recvBufByteN)) != kOkRC )
goto errLabel;
if((rc = thread::create( p->threadH, threadCallback, p)) != kOkRC )
if((rc = thread::create( p->threadH, threadCallback, p, "serial_srv")) != kOkRC )
goto errLabel;
p->pollPeriodMs = pollPeriodMs;

View File

@ -1211,7 +1211,7 @@ cw::rc_t cw::socksrv::createMgrSrv( handle_t& hRef, unsigned timeOutMs, unsigne
goto errLabel;
// create the thread
if((rc = thread::create( p->thH, _threadFunc, p)) != kOkRC )
if((rc = thread::create( p->thH, _threadFunc, p, "sock")) != kOkRC )
goto errLabel;
p->timeOutMs = timeOutMs;

View File

@ -110,7 +110,7 @@ cw::rc_t cw::net::srv::create(
if((rc = socket::create( p->sockH, port, flags, timeOutMs, remoteAddr, remotePort, localAddr )) != kOkRC )
goto errLabel;
if((rc = thread::create( p->threadH, _threadFunc, p )) != kOkRC )
if((rc = thread::create( p->threadH, _threadFunc, p, "tcp_sock_srv" )) != kOkRC )
goto errLabel;
p->flags = srvFlags;

View File

@ -120,7 +120,7 @@ cw::rc_t cw::net::socket::test( portNumber_t localPort, const char* remoteAddr,
if((rc = create(app.sockH,localPort, kBlockingFl,timeOutMs, NULL, kInvalidPortNumber )) != kOkRC )
return rc;
if((rc = thread::create( app.threadH, _dgramThreadFunc, &app )) != kOkRC )
if((rc = thread::create( app.threadH, _dgramThreadFunc, &app, "tcp_sock_test_tcp" )) != kOkRC )
goto errLabel;
if((rc = thread::unpause( app.threadH )) != kOkRC )
@ -176,7 +176,7 @@ cw::rc_t cw::net::socket::test_tcp( portNumber_t localPort, const char* remoteAd
return rc;
// create the listening thread (which is really only used by the server)
if((rc = thread::create( app.threadH, streamFl ? _tcpStreamThreadFunc : _dgramThreadFunc, &app )) != kOkRC )
if((rc = thread::create( app.threadH, streamFl ? _tcpStreamThreadFunc : _dgramThreadFunc, &app, "tcp_sock_test" )) != kOkRC )
goto errLabel;
// if this is a streaming client then connect to the server (which must have already been started)

View File

@ -31,6 +31,7 @@ namespace cw
unsigned pauseMicros;
unsigned sleepMicros;
pthread_attr_t attr;
char* label;
} thread_t;
@ -120,7 +121,7 @@ namespace cw
}
cw::rc_t cw::thread::create( handle_t& hRef, cbFunc_t func, void* funcArg, int stateMicros, int pauseMicros )
cw::rc_t cw::thread::create( handle_t& hRef, cbFunc_t func, void* funcArg, const char* label, int stateMicros, int pauseMicros )
{
rc_t rc;
int sysRC;
@ -136,6 +137,7 @@ cw::rc_t cw::thread::create( handle_t& hRef, cbFunc_t func, void* funcArg, int s
p->pauseMicros = pauseMicros;
p->stateId = kPausedThId;
p->sleepMicros = 15000;
p->label = mem::duplStr(label);
if((sysRC = pthread_attr_init(&p->attr)) != 0)
{
@ -163,7 +165,15 @@ cw::rc_t cw::thread::create( handle_t& hRef, cbFunc_t func, void* funcArg, int s
}
}
if( label != nullptr )
pthread_setname_np(p->pThreadH, label);
hRef.set(p);
cwLogInfo("Thread %s id:%p created.",cwStringNullGuard(label), p->pThreadH);
return rc;
}
@ -182,16 +192,16 @@ cw::rc_t cw::thread::destroy( handle_t& hRef )
// wait for the thread to exit and then deallocate the thread object
if((rc = _waitForState(p,kExitedThId)) != kOkRC )
return cwLogError(rc,"Thread timed out waiting for destroy.");
return cwLogError(rc,"Thread '%s' timed out waiting for destroy.",p->label);
// Block until the thread is actually fully cleaned up
if((sysRC = pthread_join(p->pThreadH,NULL)) != 0)
rc = cwLogSysError(kOpFailRC,sysRC,"Thread join failed.");
rc = cwLogSysError(kOpFailRC,sysRC,"Thread '%s' join failed.",p->label);
//if( pthread_attr_destroy(&p->attr) != 0 )
// rc = cwLogError(kOpFailRC,"Thread attribute destroy failed.");
mem::release(p->label);
mem::release(p);
hRef.clear();
@ -227,7 +237,7 @@ cw::rc_t cw::thread::pause( handle_t h, unsigned cmdFlags )
rc = _waitForState(p,waitId);
if( rc != kOkRC )
cwLogError(rc,"Thread timed out waiting for '%s'. pauseMicros:%i stateMicros:%i sleepMicros:%i", pauseFl ? "pause" : "un-pause",p->pauseMicros,p->stateMicros,p->sleepMicros);
cwLogError(rc,"Thread '%s' timed out waiting for '%s'. pauseMicros:%i stateMicros:%i sleepMicros:%i", p->label, pauseFl ? "pause" : "un-pause",p->pauseMicros,p->stateMicros,p->sleepMicros);
return rc;
@ -258,6 +268,13 @@ cw::thread::thread_id_t cw::thread::id()
return id.u.id;
}
const char* cw::thread::label( handle_t h )
{
thread_t* p = _handleToPtr(h);
return p->label==nullptr ? "<no_thread_label>" : p->label;
}
unsigned cw::thread::stateTimeOutMicros( handle_t h)
{
thread_t* p = _handleToPtr(h);
@ -288,7 +305,7 @@ cw::rc_t cw::threadTest()
rc_t rc;
char c = 0;
if((rc = thread::create(h,_threadTestCb,&val)) != kOkRC )
if((rc = thread::create(h,_threadTestCb,&val,"thread_test")) != kOkRC )
return rc;
if((rc = thread::pause(h,0)) != kOkRC )

View File

@ -5,6 +5,8 @@ namespace cw
{
namespace thread
{
const int kDefaultStateTimeOutMicros=100000;
const int kDefaultPauseMicros = 10000;
typedef enum
{
kNotInitThId,
@ -23,7 +25,13 @@ namespace cw
// The thread is in the 'paused' state after it is created.
// stateMicros = total time out duration for switching to the exit state or for switching in/out of pause state.
// pauseMicros = duration of thread sleep interval when in paused state.
rc_t create( handle_t& hRef, cbFunc_t func, void* funcArg, int stateTimeOutMicros=100000, int pauseMicros=10000 );
rc_t create( handle_t& hRef,
cbFunc_t func,
void* funcArg,
const char* label, // Assign a label which will show up via `top -H` or `ps -T`.
int stateTimeOutMicros=kDefaultStateTimeOutMicros,
int pauseMicros=kDefaultPauseMicros );
rc_t destroy( handle_t& hRef );
@ -35,6 +43,7 @@ namespace cw
// Return the thread id of the calling context.
thread_id_t id();
const char* label( handle_t h );
unsigned stateTimeOutMicros( handle_t h);
unsigned pauseMicros( handle_t h );

View File

@ -25,13 +25,13 @@ namespace cw
thread_mach_t* _handleToPtr( handle_t h )
{ return handleToPtr<handle_t,thread_mach_t>(h); }
rc_t _add( thread_mach_t* p, threadFunc_t func, void* arg )
rc_t _add( thread_mach_t* p, threadFunc_t func, void* arg, const char* label )
{
rc_t rc = kOkRC;
thread_t* t = mem::allocZ<thread_t>();
if((rc = thread::create(t->thH, func, arg )) != kOkRC )
if((rc = thread::create(t->thH, func, arg, label==nullptr ? "thread_mach" : label )) != kOkRC )
{
rc = cwLogError(rc,"Thread create failed.");
goto errLabel;
@ -90,7 +90,7 @@ cw::rc_t cw::thread_mach::create( handle_t& hRef, threadFunc_t threadFunc, void*
{
void* arg = ctxA + (i*contexRecdByteN);
if((rc = _add(p, threadFunc, arg)) != kOkRC )
if((rc = _add(p, threadFunc, arg, nullptr)) != kOkRC )
goto errLabel;
}
@ -103,10 +103,10 @@ cw::rc_t cw::thread_mach::create( handle_t& hRef, threadFunc_t threadFunc, void*
return rc;
}
cw::rc_t cw::thread_mach::add( handle_t h, threadFunc_t threadFunc, void* arg )
cw::rc_t cw::thread_mach::add( handle_t h, threadFunc_t threadFunc, void* arg, const char* label )
{
thread_mach_t* p = _handleToPtr(h);
return _add(p,threadFunc,arg);
return _add(p,threadFunc,arg, label);
}
cw::rc_t cw::thread_mach::destroy( handle_t& hRef )

View File

@ -16,7 +16,7 @@ namespace cw
// Create an additional thread. Note that the additional thread will be started by the next
// call to 'start()'.
rc_t add( handle_t h, threadFunc_t threadFunc, void* arg );
rc_t add( handle_t h, threadFunc_t threadFunc, void* arg, const char* label );
// Start all threads
rc_t start( handle_t h );

View File

@ -68,7 +68,7 @@ cw::rc_t cw::websockSrv::create(
goto errLabel;
if((rc = thread::create(p->_thread,_websockSrvThreadCb,p)) != kOkRC )
if((rc = thread::create(p->_thread,_websockSrvThreadCb,p,"web_sock_srv")) != kOkRC )
goto errLabel;
p->_timeOutMs = timeOutMs;