1#include <TestShell.h>
2#include <ThreadedTestCase.h>
3#include <Autolock.h>
4#include <stdio.h>
5#include <stdarg.h>
6
7using std::map;
8using std::string;
9using std::vector;
10
11_EXPORT
12BThreadedTestCase::BThreadedTestCase(string name, string progressSeparator)
13	: BTestCase(name)
14	, fInUse(false)
15	, fProgressSeparator(progressSeparator)
16	, fUpdateLock(new BLocker())
17{
18}
19
20_EXPORT
21BThreadedTestCase::~BThreadedTestCase() {
22	// Kill our locker
23	delete fUpdateLock;
24
25	// Clean up
26	for (map<thread_id, ThreadSubTestInfo*>::iterator i = fNumberMap.begin();
27		   i != fNumberMap.end();
28		     i++)
29	{
30		delete i->second;
31	}
32}
33
34_EXPORT
35void
36BThreadedTestCase::NextSubTest() {
37	// Find out what thread we're in
38	thread_id id = find_thread(NULL);
39
40	{
41		// Acquire the update lock
42		BAutolock lock(fUpdateLock);
43		map<thread_id, ThreadSubTestInfo*>::iterator i = fNumberMap.find(id);
44		if (i != fNumberMap.end() && i->second) {
45			// Handle multi-threaded case
46			ThreadSubTestInfo *info = i->second;
47			char num[32];
48			sprintf(num, "%ld", info->subTestNum++);
49			string str = string("[") + info->name + fProgressSeparator + num + "]";
50			fUpdateList.push_back(str);
51			return;
52		}
53	}
54
55	// Handle single-threaded case
56	BTestCase::NextSubTest();
57}
58
59_EXPORT
60void
61BThreadedTestCase::Outputf(const char *str, ...) {
62	if (BTestShell::GlobalBeVerbose()) {
63		// Figure out if this is a multithreaded test or not
64		thread_id id = find_thread(NULL);
65		bool isSingleThreaded;
66		{
67			BAutolock lock(fUpdateLock);
68			isSingleThreaded = fNumberMap.find(id) == fNumberMap.end();
69		}
70		if (isSingleThreaded) {
71			va_list args;
72			va_start(args, str);
73			vprintf(str, args);
74			va_end(args);
75			fflush(stdout);
76		} else {
77			va_list args;
78			va_start(args, str);
79			char msg[1024];	// Need a longer string? Change the constant or change the function. :-)
80			vsprintf(msg, str, args);
81			va_end(args);
82			{
83				// Acquire the update lock and post our update
84				BAutolock lock(fUpdateLock);
85				fUpdateList.push_back(string(msg));
86			}
87		}
88	}
89}
90
91_EXPORT
92void
93BThreadedTestCase::InitThreadInfo(thread_id id, string threadName) {
94	BAutolock lock(fUpdateLock);	// Lock the number map
95	map<thread_id, ThreadSubTestInfo*>::iterator i = fNumberMap.find(id);
96	if (i != fNumberMap.end() && i->second) {
97		i->second->name = threadName;
98		i->second->subTestNum = 0;
99	} else {
100		// New addition
101		ThreadSubTestInfo *info = new ThreadSubTestInfo();
102		info->name = threadName;
103		info->subTestNum = 0;
104		fNumberMap[id] = info;
105	}
106}
107
108_EXPORT
109bool
110BThreadedTestCase::RegisterForUse() {
111	if (!fInUse) {
112		fInUse = true;
113		return true;
114	} else
115		return false;
116}
117
118_EXPORT
119void
120BThreadedTestCase::UnregisterForUse() {
121	fInUse = false;
122}
123
124_EXPORT
125vector<string>&
126BThreadedTestCase::AcquireUpdateList() {
127	fUpdateLock->Lock();
128	return fUpdateList;
129}
130
131_EXPORT
132void
133BThreadedTestCase::ReleaseUpdateList() {
134	fUpdateLock->Unlock();
135}
136