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