[interfacekit] Re: A patch for BString
- From: Oliver Tappe <openbeos@xxxxxxxxxxxxxxx>
- To: interfacekit@xxxxxxxxxxxxx
- Date: Sat, 08 Nov 2003 00:05:21 +0100
On 2003-11-06 at 21:36:18 [+0100], Ingo Weinhold wrote:
>
>
> > BString s;
> > CPPUNIT_ASSERT_DEBUGGER( s.Insert( "dummy", 20));
> >
> > Does this kind of stuff already exist in cppunit? Is it feasible at all?
>
> AFAIK, it is not implemented and at the time I hit this problem myself (a
> year or so ago) I thought it wasn't possible to solve... Now I know better.
> :-)
>
> Catching signals doesn't seem to work -- I wrote a little test handler
> catching any signal, but a debugger call isn't caught. What probably will
> work is to install a debugger (cf. <debugger.h>), but it's quite a bit of
> overhead, for the debugger must live in another team (how I understand it).
>
> A better solution seems to redirect the debugger() invocation. By accident,
> not too long ago, I wrote some code that allows to redirect calls to
> functions that live in a different shared object at least. Since debugger()
> is defined in libroot, that should be just fine for invocations from
> libbe/libopenbeos.
>
> If noone objects, I can try and extend our unit test framework to support
> testing for debugger calls.
Out of curiosity, I have fiddled a bit with the stuff in <debugger.h> and it
seems that you can install a debugger inside your own team, all you need is a
new thread.
Enclosed you find a proof-of-concept.
There is one problem, though: if the application crashes (e.g. seg-faults)
the dummy-debugger gets invoked, too.
My implementation in that case notices that is has been called for the wrong
reason and tries to fall back to the default debugger, but that doesn't seem
to work from inside the debugger: nothing happens.
So we should probably go with Ingo's solution as it seems more reliable, but
it may be worthwile to invest some more time into the debugger-stuff.
BTW: Is anyone working on something like bdb for OBOS (or should the original
just run fine)?
cheers,
Oliver#include <cstring>
#include <iostream>
#include <assert.h>
#include <debugger.h>
#include <Debug.h>
#include <List.h>
#include <Locker.h>
#define ASSERT_DEBUGGER_CALL( expr) \
{ \
thread_id tid = find_thread( NULL); \
testDebugger.ClearThreadHasCalledDebugger( tid); \
expr; \
if (!testDebugger.ThreadHasCalledDebugger( tid)) \
cerr << "assertion failed" << endl; \
}
struct TestTeamDebugger {
TestTeamDebugger();
~TestTeamDebugger();
status_t InitCheck() const { return
fInitCheck; }
bool ThreadHasCalledDebugger( thread_id tid);
void SetThreadHasCalledDebugger( thread_id tid);
void ClearThreadHasCalledDebugger( thread_id tid);
private:
static int32 StartDebuggerThread( void* data);
void InstallDebugger();
void RemoveDebugger();
int32 RunDebugger();
status_t fInitCheck;
port_id fDebugPort;
port_id fOriginalDebugPort;
thread_id fDebugThread;
team_id fMyTeam;
BLocker fThreadDataLocker;
BList fThreadData;
bool fShutdown;
enum {
SYNC_DEBUGGER = 'sDbg'
};
};
TestTeamDebugger::TestTeamDebugger()
: fInitCheck( B_NO_INIT)
, fDebugPort( 0)
, fDebugThread( 0)
, fMyTeam( 0)
, fThreadDataLocker( "TestTeamDebugger")
, fShutdown( false)
{
fDebugThread = spawn_thread( StartDebuggerThread,
"TestTeamDebugThread",
B_NORMAL_PRIORITY, (void*)this);
if (!fDebugThread) {
fInitCheck = fDebugThread;
return;
}
if ((fInitCheck = send_data( fDebugThread, SYNC_DEBUGGER, NULL, 0)) < 0)
return;
if ((fInitCheck = resume_thread( fDebugThread)) < 0)
return;
thread_id sender;
if ((fInitCheck = receive_data( &sender, NULL, 0)) != SYNC_DEBUGGER)
return;
}
TestTeamDebugger::~TestTeamDebugger() {
fShutdown = true;
if (fDebugThread) {
status_t result;
wait_for_thread( fDebugThread, &result);
}
}
bool TestTeamDebugger::ThreadHasCalledDebugger( thread_id tid) {
fThreadDataLocker.Lock();
bool result = fThreadData.HasItem( (void*)tid);
fThreadDataLocker.Unlock();
return result;
}
void TestTeamDebugger::SetThreadHasCalledDebugger( thread_id tid) {
fThreadDataLocker.Lock();
if (!fThreadData.HasItem( (void*)tid))
fThreadData.AddItem( (void*)tid);
fThreadDataLocker.Unlock();
}
void TestTeamDebugger::ClearThreadHasCalledDebugger( thread_id tid) {
fThreadDataLocker.Lock();
fThreadData.RemoveItem( (void*)tid);
fThreadDataLocker.Unlock();
}
int32 TestTeamDebugger::StartDebuggerThread( void* data) {
status_t err;
TestTeamDebugger* dbg = reinterpret_cast<TestTeamDebugger*>( data);
thread_id sender;
if ((dbg->fInitCheck = receive_data( &sender, NULL, 0)) !=
SYNC_DEBUGGER)
return dbg->fInitCheck;
dbg->InstallDebugger();
if ((dbg->fInitCheck = send_data( sender, SYNC_DEBUGGER, NULL, 0)) < 0)
return dbg->fInitCheck;
if (dbg->fInitCheck == B_OK)
dbg->RunDebugger();
dbg->RemoveDebugger();
return dbg->fInitCheck;
}
void TestTeamDebugger::InstallDebugger() {
if ((fDebugPort = create_port( 10, "TestTeamDebuggerPort")) < 0) {
fInitCheck = fDebugPort;
return;
}
thread_info tInfo;
if ((fInitCheck = get_thread_info( find_thread(NULL), &tInfo)) < 0)
return;
fMyTeam = tInfo.team;
status_t err = install_team_debugger( fMyTeam, fDebugPort);
if (err < 0)
fInitCheck = err;
}
void TestTeamDebugger::RemoveDebugger() {
if (fMyTeam) {
fInitCheck = remove_team_debugger( fMyTeam);
fMyTeam = 0;
}
if (fDebugPort) {
fInitCheck = close_port( fDebugPort);
fDebugPort = 0;
}
}
int32 TestTeamDebugger::RunDebugger() {
status_t err;
size_t bufSize;
int32 msgCode;
while( !fShutdown) {
do {
bufSize = port_buffer_size_etc( fDebugPort, B_TIMEOUT,
100*1000);
if (bufSize < 0 && bufSize != B_TIMED_OUT)
return bufSize;
if (fShutdown)
return B_OK;
} while (bufSize == B_TIMED_OUT);
char msgBuf[bufSize];
ssize_t readLen = read_port( fDebugPort, &msgCode, &msgBuf,
bufSize);
if (readLen < 0)
return readLen;
switch (msgCode) {
case B_THREAD_STOPPED: {
// the system tells us that it has stopped a
thread,
// first we check why...
db_thread_stopped_msg* stoppedInfo =
(db_thread_stopped_msg*)msgBuf;
if (stoppedInfo->why == B_DEBUGGER_CALL) {
// correct reason for test-debugger, so
we take notice
// which thread has called for a
debug-session:
SetThreadHasCalledDebugger(
stoppedInfo->thread);
}
// tell the nub to let the thread continue:
nub_run_thread_msg runInfo;
runInfo.thread = stoppedInfo->thread;
runInfo.cpu = stoppedInfo->cpu;
if ((err = write_port( stoppedInfo->nub_port,
B_RUN_THREAD,
(void*)&runInfo, sizeof(runInfo))) < 0) {
cerr << "TestTeamDebugger: error in
write_port: "
<< strerror( err) << endl;
return err;
}
if (stoppedInfo->why != B_DEBUGGER_CALL) {
// ugh, wrong reason, we don't want to
handle this (real) error,
// so we remove ourselves and fallback
to the real debugger:
cerr << "TestTeamDebugger: called for
unexpected reason "
<< stoppedInfo->why << ",
calling real debugger!" << endl;
RemoveDebugger();
fShutdown = true;
}
break;
}
default:
cerr << "TestTeamDebugger: read unexpected code
" << msgCode
<< "from nub-port, it's ignored!" <<
endl;
};
}
return B_OK;
}
int main() {
TestTeamDebugger testDebugger;
status_t err = testDebugger.InitCheck();
if (err < 0) {
cerr << "Creation of TestTeamDebugger failed: " << strerror(
err) << endl;
exit( 5);
}
ASSERT_DEBUGGER_CALL( debugger("Hello debugger!"));
cout << "back from the living dead!" << endl;
ASSERT_DEBUGGER_CALL( cout << "should fail..." << endl);
}
- Follow-Ups:
- [interfacekit] Re: A patch for BString
- From: Axel Dörfler
- [interfacekit] Re: A patch for BString
- From: Ingo Weinhold
- References:
- [interfacekit] A patch for BString
- From: Oliver Tappe
- [interfacekit] Re: A patch for BString
- From: Ingo Weinhold
Other related posts:
- » [interfacekit] A patch for BString
- » [interfacekit] Re: A patch for BString
- » [interfacekit] Re: A patch for BString
- » [interfacekit] Re: A patch for BString
- » [interfacekit] Re: A patch for BString
- » [interfacekit] Re: A patch for BString
- » [interfacekit] Re: A patch for BString
- » [interfacekit] Re: A patch for BString
- » [interfacekit] Re: A patch for BString
- » [interfacekit] Re: A patch for BString
- » [interfacekit] Re: A patch for BString
- » [interfacekit] Re: A patch for BString
- » [interfacekit] Re: A patch for BString
- » [interfacekit] Re: A patch for BString
- » [interfacekit] Re: A patch for BString
- » [interfacekit] Re: A patch for BString
- » [interfacekit] Re: A patch for BString
- » [interfacekit] Re: A patch for BString
- » [interfacekit] Re: A patch for BString
- » [interfacekit] Re: A patch for BString
- » [interfacekit] Re: A patch for BString
- » [interfacekit] Re: A patch for BString
- » [interfacekit] Re: A patch for BString
- [interfacekit] Re: A patch for BString
- From: Axel Dörfler
- [interfacekit] Re: A patch for BString
- From: Ingo Weinhold
- [interfacekit] A patch for BString
- From: Oliver Tappe
- [interfacekit] Re: A patch for BString
- From: Ingo Weinhold