xref: /haiku/src/tests/kits/app/broster/LaunchTesterHelper.cpp (revision 77aa0e2a5ef8e6d00570dbeb7a12aeb23e9e5cf0)
1 //	LaunchTesterHelper.cpp
2 
3 #include <stdio.h>
4 #include <string.h>
5 
6 #include <Autolock.h>
7 #include <Entry.h>
8 #include <List.h>
9 #include <Message.h>
10 #include <Messenger.h>
11 #include <Path.h>
12 
13 #include "LaunchTesterHelper.h"
14 #include "RosterTestAppDefs.h"
15 
16 /////////////////
17 // LaunchContext
18 
19 const char *LaunchContext::kStandardArgv[] = {
20 	"Some", "nice", "arguments"
21 };
22 const int32 LaunchContext::kStandardArgc
23 	= sizeof(kStandardArgv) / sizeof(const char*);
24 
25 // Message
26 class LaunchContext::Message {
27 public:
28 	BMessage	message;
29 	bigtime_t	when;
30 };
31 
32 // Sleeper
33 class LaunchContext::Sleeper {
34 public:
Sleeper()35 	Sleeper() : fMessageCode(0), fSemaphore(-1) {}
36 
~Sleeper()37 	~Sleeper()
38 	{
39 		delete_sem(fSemaphore);
40 	}
41 
Init(uint32 messageCode)42 	status_t Init(uint32 messageCode)
43 	{
44 		fMessageCode = messageCode;
45 		fSemaphore = create_sem(0, "sleeper sem");
46 		return (fSemaphore >= 0 ? B_OK : fSemaphore);
47 	}
48 
MessageCode() const49 	uint32 MessageCode() const { return fMessageCode; }
50 
Sleep(bigtime_t timeout=B_INFINITE_TIMEOUT)51 	status_t Sleep(bigtime_t timeout = B_INFINITE_TIMEOUT)
52 	{
53 		return acquire_sem_etc(fSemaphore, 1, B_RELATIVE_TIMEOUT, timeout);
54 	}
55 
WakeUp()56 	status_t WakeUp()
57 	{
58 		return release_sem(fSemaphore);
59 	}
60 
61 private:
62 	uint32		fMessageCode;
63 	sem_id		fSemaphore;
64 };
65 
66 // AppInfo
67 class LaunchContext::AppInfo {
68 public:
AppInfo(team_id team)69 	AppInfo(team_id team)
70 		: fTeam(team),
71 		  fMessenger(),
72 		  fMessages(),
73 		  fTerminating(false)
74 	{
75 	}
76 
~AppInfo()77 	~AppInfo()
78 	{
79 		for (int32 i = 0; LaunchContext::Message *message = MessageAt(i); i++)
80 			delete message;
81 	}
82 
Team() const83 	team_id Team() const
84 	{
85 		return fTeam;
86 	}
87 
SetMessenger(BMessenger messenger)88 	void SetMessenger(BMessenger messenger)
89 	{
90 		fMessenger = messenger;
91 	}
92 
Messenger() const93 	BMessenger Messenger() const
94 	{
95 		return fMessenger;
96 	}
97 
Terminate()98 	void Terminate()
99 	{
100 		if (!fTerminating && fMessenger.IsValid())
101 		{
102 			fTerminating = true;
103 			fMessenger.SendMessage(B_QUIT_REQUESTED);
104 		}
105 	}
106 
AddMessage(const BMessage & _message)107 	void AddMessage(const BMessage &_message)
108 	{
109 		LaunchContext::Message *message = new LaunchContext::Message;
110 		message->message = _message;
111 		message->when = system_time();
112 		fMessages.AddItem(message);
113 		NotifySleepers(_message.what);
114 	}
115 
RemoveMessage(int32 index)116 	LaunchContext::Message *RemoveMessage(int32 index)
117 	{
118 		return (LaunchContext::Message*)fMessages.RemoveItem(index);
119 	}
120 
MessageAt(int32 index) const121 	LaunchContext::Message *MessageAt(int32 index) const
122 	{
123 		return (LaunchContext::Message*)fMessages.ItemAt(index);
124 	}
125 
FindMessage(uint32 messageCode,int32 startIndex=0) const126 	LaunchContext::Message *FindMessage(uint32 messageCode,
127 										int32 startIndex = 0) const
128 	{
129 		LaunchContext::Message *message = NULL;
130 		for (int32 i = startIndex; (message = MessageAt(i)) != NULL; i++) {
131 			if (message->message.what == messageCode)
132 				break;
133 		}
134 		return message;
135 	}
136 
AddSleeper(Sleeper * sleeper)137 	void AddSleeper(Sleeper *sleeper)
138 	{
139 		fSleepers.AddItem(sleeper);
140 	}
141 
RemoveSleeper(Sleeper * sleeper)142 	void RemoveSleeper(Sleeper *sleeper)
143 	{
144 		fSleepers.RemoveItem(sleeper);
145 	}
146 
NotifySleepers(uint32 messageCode)147 	void NotifySleepers(uint32 messageCode)
148 	{
149 		for (int32 i = 0;
150 			 Sleeper *sleeper = (Sleeper*)fSleepers.ItemAt(i);
151 			 i++) {
152 			if (sleeper->MessageCode() == messageCode)
153 				sleeper->WakeUp();
154 		}
155 	}
156 
157 private:
158 	team_id		fTeam;
159 	BMessenger	fMessenger;
160 	BList		fMessages;
161 	bool		fTerminating;
162 	BList		fSleepers;
163 };
164 
165 // constructor
LaunchContext()166 LaunchContext::LaunchContext()
167 	: fAppInfos(),
168 	  fSleepers(),
169 	  fLock(),
170 	  fAppThread(B_ERROR),
171 	  fTerminator(B_ERROR),
172 	  fTerminating(false)
173 {
174 	RosterLaunchApp *app = dynamic_cast<RosterLaunchApp*>(be_app);
175 	app->SetLaunchContext(this);
176 	app->Unlock();
177 	fAppThread = spawn_thread(AppThreadEntry, "app thread", B_NORMAL_PRIORITY,
178 							  this);
179 	if (fAppThread >= 0) {
180 		status_t error = resume_thread(fAppThread);
181 		if (error != B_OK)
182 			printf("ERROR: Couldn't resume app thread: %s\n", strerror(error));
183 	} else
184 		printf("ERROR: Couldn't spawn app thread: %s\n", strerror(fAppThread));
185 }
186 
187 // destructor
~LaunchContext()188 LaunchContext::~LaunchContext()
189 {
190 	Terminate();
191 	// cleanup
192 	for (int32 i = 0; AppInfo *info = AppInfoAt(i); i++)
193 		delete info;
194 	for (int32 i = 0;
195 		 BMessage *message = (BMessage*)fStandardMessages.ItemAt(i);
196 		 i++) {
197 		delete message;
198 	}
199 }
200 
201 // ()
202 status_t
operator ()(LaunchCaller & caller,const char * type,team_id * team)203 LaunchContext::operator()(LaunchCaller &caller, const char *type,
204 						  team_id *team)
205 {
206 	BMessage message1(MSG_1);
207 	BMessage message2(MSG_2);
208 	BMessage message3(MSG_3);
209 	BList messages;
210 	messages.AddItem(&message1);
211 	messages.AddItem(&message2);
212 	messages.AddItem(&message3);
213 	return (*this)(caller, type, &messages, kStandardArgc, kStandardArgv,
214 				   team);
215 }
216 
217 // ()
218 status_t
operator ()(LaunchCaller & caller,const char * type,BList * messages,int32 argc,const char ** argv,team_id * team)219 LaunchContext::operator()(LaunchCaller &caller, const char *type,
220 						  BList *messages, int32 argc, const char **argv,
221 						  team_id *team)
222 {
223 	BAutolock _lock(fLock);
224 	status_t result = caller(type, messages, argc, argv, team);
225 	if (result == B_OK && team)
226 		CreateAppInfo(*team);
227 	return result;
228 }
229 
230 // HandleMessage
231 void
HandleMessage(BMessage * message)232 LaunchContext::HandleMessage(BMessage *message)
233 {
234 //printf("LaunchContext::HandleMessage(%6ld: %.4s)\n",
235 //message->ReturnAddress().Team(), (char*)&message->what);
236 //if (message->what == MSG_MESSAGE_RECEIVED) {
237 //	BMessage sentMessage;
238 //	message->FindMessage("message", &sentMessage);
239 //	team_id sender = -1;
240 //	message->FindInt32("sender", &sender);
241 //	printf("  <- %6ld: %.4s\n", sender, (char*)&sentMessage.what);
242 //}
243 
244 	BAutolock _lock(fLock);
245 	switch (message->what) {
246 		case MSG_STARTED:
247 		case MSG_TERMINATED:
248 		case MSG_MAIN_ARGS:
249 		case MSG_ARGV_RECEIVED:
250 		case MSG_REFS_RECEIVED:
251 		case MSG_MESSAGE_RECEIVED:
252 		case MSG_QUIT_REQUESTED:
253 		case MSG_READY_TO_RUN:
254 		case MSG_1:
255 		case MSG_2:
256 		case MSG_3:
257 		case MSG_REPLY:
258 		{
259 			BMessenger messenger = message->ReturnAddress();
260 			// add the message to the respective team's message list
261 			// Note: catch messages that have not been sent by us or the
262 			// remote team. The R5 registrar seems to send a B_REPLY message
263 			// sometimes.
264 			team_id sender = -1;
265 			bool dontIgnore = false;
266 			if (message->FindInt32("sender", &sender) != B_OK
267 				|| sender == be_app->Team()
268 				|| sender == messenger.Team()
269 				|| (message->FindBool("don't ignore", &dontIgnore) == B_OK)
270 					&& dontIgnore) {
271 				AppInfo *info = CreateAppInfo(messenger);
272 				info->AddMessage(*message);
273 				if (fTerminating)
274 					TerminateApp(info);
275 			}
276 			NotifySleepers(message->what);
277 			break;
278 		}
279 		default:
280 			break;
281 	}
282 }
283 
284 // Terminate
285 void
Terminate()286 LaunchContext::Terminate()
287 {
288 	fLock.Lock();
289 	if (!fTerminating) {
290 		fTerminating = true;
291 		// tell all test apps to quit
292 		for (int32 i = 0; AppInfo *info = AppInfoAt(i); i++)
293 			TerminateApp(info);
294 		// start terminator
295 		fTerminator = spawn_thread(TerminatorEntry, "terminator",
296 								   B_NORMAL_PRIORITY, this);
297 		if (fTerminator >= 0) {
298 			status_t error = resume_thread(fTerminator);
299 			if (error != B_OK) {
300 				printf("ERROR: Couldn't resume terminator thread: %s\n",
301 					   strerror(error));
302 			}
303 		} else {
304 			printf("ERROR: Couldn't spawn terminator thread: %s\n",
305 				   strerror(fTerminator));
306 		}
307 	}
308 	fLock.Unlock();
309 	// wait for the app to terminate
310 	int32 dummy;
311 	wait_for_thread(fAppThread, &dummy);
312 	wait_for_thread(fTerminator, &dummy);
313 }
314 
315 // TerminateApp
316 void
TerminateApp(team_id team,bool wait)317 LaunchContext::TerminateApp(team_id team, bool wait)
318 {
319 	fLock.Lock();
320 	if (AppInfo *info = AppInfoFor(team))
321 		TerminateApp(info);
322 	fLock.Unlock();
323 	if (wait)
324 		WaitForMessage(team, MSG_TERMINATED);
325 }
326 
327 // TeamAt
328 team_id
TeamAt(int32 index) const329 LaunchContext::TeamAt(int32 index) const
330 {
331 	BAutolock _lock(fLock);
332 	team_id team = B_ERROR;
333 	if (AppInfo *info = AppInfoAt(index))
334 		team = info->Team();
335 	return team;
336 }
337 
338 // AppMessengerFor
339 BMessenger
AppMessengerFor(team_id team) const340 LaunchContext::AppMessengerFor(team_id team) const
341 {
342 	BAutolock _lock(fLock);
343 	BMessenger result;
344 	if (AppInfoFor(team)) {
345 		// We need to do some hacking.
346 		BMessenger messenger;
347 		struct fake_messenger {
348 			port_id	fPort;
349 			int32	fHandlerToken;
350 			team_id	fTeam;
351 			int32	extra0;
352 			int32	extra1;
353 			bool	fPreferredTarget;
354 			bool	extra2;
355 			bool	extra3;
356 			bool	extra4;
357 		} &fake = *(fake_messenger*)&messenger;
358 		status_t error = B_OK;
359 		fake.fTeam = team;
360 		// find app looper port
361 		bool found = false;
362 		int32 cookie = 0;
363 		port_info info;
364 		while (error == B_OK && !found) {
365 			error = get_next_port_info(fake.fTeam, &cookie, &info);
366 			found = (error == B_OK
367 					 && (!strcmp("AppLooperPort", info.name)
368 					 	 || !strcmp("rAppLooperPort", info.name)));
369 		}
370 		// init messenger
371 		if (error == B_OK) {
372 			fake.fPort = info.port;
373 			fake.fHandlerToken = 0;
374 			fake.fPreferredTarget = true;
375 		}
376 		if (error == B_OK)
377 			result = messenger;
378 	}
379 	return result;
380 }
381 
382 // NextMessageFrom
383 BMessage*
NextMessageFrom(team_id team,int32 & cookie,bigtime_t * time)384 LaunchContext::NextMessageFrom(team_id team, int32 &cookie, bigtime_t *time)
385 {
386 	BAutolock _lock(fLock);
387 	BMessage *message = NULL;
388 	if (AppInfo *info = AppInfoFor(team)) {
389 		if (Message *contextMessage = info->MessageAt(cookie++))
390 			message = &contextMessage->message;
391 	}
392 	return message;
393 }
394 
395 // CheckNextMessage
396 bool
CheckNextMessage(LaunchCaller & caller,team_id team,int32 & cookie,uint32 what)397 LaunchContext::CheckNextMessage(LaunchCaller &caller, team_id team,
398 								int32 &cookie, uint32 what)
399 {
400 	BMessage *message = NextMessageFrom(team, cookie);
401 	return (message && message->what == what);
402 }
403 
404 // CheckMainArgsMessage
405 bool
CheckMainArgsMessage(LaunchCaller & caller,team_id team,int32 & cookie,const entry_ref * appRef,bool useRef)406 LaunchContext::CheckMainArgsMessage(LaunchCaller &caller, team_id team,
407 								int32 &cookie, const entry_ref *appRef,
408 								bool useRef)
409 {
410 	int32 argc = 0;
411 	const char **argv = NULL;
412 	if (caller.SupportsArgv()) {
413 		argc = kStandardArgc;
414 		argv = kStandardArgv;
415 	}
416 	return CheckMainArgsMessage(caller, team, cookie, appRef, argc, argv,
417 								useRef);
418 }
419 
420 // CheckMainArgsMessage
421 bool
CheckMainArgsMessage(LaunchCaller & caller,team_id team,int32 & cookie,const entry_ref * appRef,int32 argc,const char ** argv,bool useRef)422 LaunchContext::CheckMainArgsMessage(LaunchCaller &caller, team_id team,
423 								int32 &cookie, const entry_ref *appRef,
424 								int32 argc, const char **argv, bool useRef)
425 {
426 	useRef &= caller.SupportsArgv() && argv && argc > 0;
427 	const entry_ref *ref = (useRef ? caller.Ref() : NULL);
428 	return CheckArgsMessage(caller, team, cookie, appRef, ref, argc, argv,
429 							MSG_MAIN_ARGS);
430 }
431 
432 // CheckArgvMessage
433 bool
CheckArgvMessage(LaunchCaller & caller,team_id team,int32 & cookie,const entry_ref * appRef,bool useRef)434 LaunchContext::CheckArgvMessage(LaunchCaller &caller, team_id team,
435 								int32 &cookie, const entry_ref *appRef,
436 								bool useRef)
437 {
438 	bool result = true;
439 	if (caller.SupportsArgv()) {
440 		result = CheckArgvMessage(caller, team, cookie, appRef, kStandardArgc,
441 								  kStandardArgv, useRef);
442 	}
443 	return result;
444 }
445 
446 // CheckArgvMessage
447 bool
CheckArgvMessage(LaunchCaller & caller,team_id team,int32 & cookie,const entry_ref * appRef,int32 argc,const char ** argv,bool useRef)448 LaunchContext::CheckArgvMessage(LaunchCaller &caller, team_id team,
449 								int32 &cookie, const entry_ref *appRef,
450 								int32 argc, const char **argv, bool useRef)
451 {
452 	const entry_ref *ref = (useRef ? caller.Ref() : NULL);
453 	return CheckArgvMessage(caller, team, cookie, appRef, ref , argc, argv);
454 }
455 
456 // CheckArgvMessage
457 bool
CheckArgvMessage(LaunchCaller & caller,team_id team,int32 & cookie,const entry_ref * appRef,const entry_ref * ref,int32 argc,const char ** argv)458 LaunchContext::CheckArgvMessage(LaunchCaller &caller, team_id team,
459 								int32 &cookie, const entry_ref *appRef,
460 								const entry_ref *ref , int32 argc,
461 								const char **argv)
462 {
463 	return CheckArgsMessage(caller, team, cookie, appRef, ref, argc, argv,
464 							MSG_ARGV_RECEIVED);
465 }
466 
467 // CheckArgsMessage
468 bool
CheckArgsMessage(LaunchCaller & caller,team_id team,int32 & cookie,const entry_ref * appRef,const entry_ref * ref,int32 argc,const char ** argv,uint32 messageCode)469 LaunchContext::CheckArgsMessage(LaunchCaller &caller, team_id team,
470 								int32 &cookie, const entry_ref *appRef,
471 								const entry_ref *ref , int32 argc,
472 								const char **argv, uint32 messageCode)
473 {
474 	BMessage *message = NextMessageFrom(team, cookie);
475 	bool result = (message && message->what == messageCode);
476 	int32 additionalRef = (ref ? 1 : 0);
477 	// check argc
478 	int32 foundArgc = -1;
479 	if (result) {
480 		result = (message->FindInt32("argc", &foundArgc) == B_OK
481 				  && foundArgc == argc + 1 + additionalRef);
482 if (!result)
483 printf("argc differ: %ld vs %ld + 1 + %ld\n", foundArgc, argc, additionalRef);
484 	}
485 	// check argv[0] (the app file name)
486 	if (result) {
487 		BPath path;
488 		const char *arg = NULL;
489 		result = (path.SetTo(appRef) == B_OK
490 				  && message->FindString("argv", 0, &arg) == B_OK
491 				  && path == arg);
492 if (!result)
493 printf("app paths differ: `%s' vs `%s'\n", arg, path.Path());
494 	}
495 	// check remaining argv
496 	for (int32 i = 1; result && i < argc; i++) {
497 		const char *arg = NULL;
498 		result = (message->FindString("argv", i, &arg) == B_OK
499 				  && !strcmp(arg, argv[i - 1]));
500 if (!result)
501 printf("arg[%ld] differ: `%s' vs `%s'\n", i, arg, argv[i - 1]);
502 	}
503 	// check additional ref
504 	if (result && additionalRef) {
505 		BPath path;
506 		const char *arg = NULL;
507 		result = (path.SetTo(ref) == B_OK
508 				  && message->FindString("argv", argc + 1, &arg) == B_OK
509 				  && path == arg);
510 if (!result)
511 printf("document paths differ: `%s' vs `%s'\n", arg, path.Path());
512 	}
513 	return result;
514 }
515 
516 // CheckMessageMessages
517 bool
CheckMessageMessages(LaunchCaller & caller,team_id team,int32 & cookie)518 LaunchContext::CheckMessageMessages(LaunchCaller &caller, team_id team,
519 									int32 &cookie)
520 {
521 	BAutolock _lock(fLock);
522 	bool result = true;
523 	for (int32 i = 0; i < 3; i++)
524 		result &= CheckMessageMessage(caller, team, cookie, i);
525 	return result;
526 }
527 
528 // CheckMessageMessage
529 bool
CheckMessageMessage(LaunchCaller & caller,team_id team,int32 & cookie,int32 index)530 LaunchContext::CheckMessageMessage(LaunchCaller &caller, team_id team,
531 								   int32 &cookie, int32 index)
532 {
533 	bool result = true;
534 	if (caller.SupportsMessages() > index && index < 3) {
535 		uint32 commands[] = { MSG_1, MSG_2, MSG_3 };
536 		BMessage message(commands[index]);
537 		result = CheckMessageMessage(caller, team, cookie, &message);
538 	}
539 	return result;
540 }
541 
542 // CheckMessageMessage
543 bool
CheckMessageMessage(LaunchCaller & caller,team_id team,int32 & cookie,const BMessage * expectedMessage)544 LaunchContext::CheckMessageMessage(LaunchCaller &caller, team_id team,
545 								   int32 &cookie,
546 								   const BMessage *expectedMessage)
547 {
548 	BMessage *message = NextMessageFrom(team, cookie);
549 	bool result = (message && message->what == MSG_MESSAGE_RECEIVED);
550 	if (result) {
551 		BMessage sentMessage;
552 		result = (message->FindMessage("message", &sentMessage) == B_OK
553 				  && sentMessage.what == expectedMessage->what);
554 	}
555 	return result;
556 }
557 
558 // CheckRefsMessage
559 bool
CheckRefsMessage(LaunchCaller & caller,team_id team,int32 & cookie)560 LaunchContext::CheckRefsMessage(LaunchCaller &caller, team_id team,
561 								int32 &cookie)
562 {
563 	bool result = true;
564 	if (caller.SupportsRefs())
565 		result = CheckRefsMessage(caller, team, cookie, caller.Ref());
566 	return result;
567 }
568 
569 // CheckRefsMessage
570 bool
CheckRefsMessage(LaunchCaller & caller,team_id team,int32 & cookie,const entry_ref * refs,int32 count)571 LaunchContext::CheckRefsMessage(LaunchCaller &caller, team_id team,
572 								int32 &cookie, const entry_ref *refs,
573 								int32 count)
574 {
575 	BMessage *message = NextMessageFrom(team, cookie);
576 	bool result = (message && message->what == MSG_REFS_RECEIVED);
577 	if (result) {
578 		entry_ref ref;
579 		for (int32 i = 0; result && i < count; i++) {
580 			result = (message->FindRef("refs", i, &ref) == B_OK
581 					  && ref == refs[i]);
582 		}
583 	}
584 	return result;
585 }
586 
587 // WaitForMessage
588 bool
WaitForMessage(uint32 messageCode,bool fromNow,bigtime_t timeout)589 LaunchContext::WaitForMessage(uint32 messageCode, bool fromNow,
590 							  bigtime_t timeout)
591 {
592 	status_t error = B_ERROR;
593 	fLock.Lock();
594 	error = B_OK;
595 	if (fromNow || !FindMessage(messageCode)) {
596 		// add sleeper
597 		Sleeper *sleeper = new Sleeper;
598 		error = sleeper->Init(messageCode);
599 		if (error == B_OK) {
600 			AddSleeper(sleeper);
601 			fLock.Unlock();
602 			// sleep
603 			error = sleeper->Sleep(timeout);
604 			fLock.Lock();
605 			// remove sleeper
606 			RemoveSleeper(sleeper);
607 			delete sleeper;
608 		}
609 	}
610 	fLock.Unlock();
611 	return (error == B_OK);
612 }
613 
614 // WaitForMessage
615 bool
WaitForMessage(team_id team,uint32 messageCode,bool fromNow,bigtime_t timeout,int32 startIndex)616 LaunchContext::WaitForMessage(team_id team, uint32 messageCode, bool fromNow,
617 							  bigtime_t timeout, int32 startIndex)
618 {
619 	status_t error = B_ERROR;
620 	fLock.Lock();
621 	if (AppInfo *info = AppInfoFor(team)) {
622 		error = B_OK;
623 		if (fromNow || !info->FindMessage(messageCode, startIndex)) {
624 			// add sleeper
625 			Sleeper *sleeper = new Sleeper;
626 			error = sleeper->Init(messageCode);
627 			if (error == B_OK) {
628 				info->AddSleeper(sleeper);
629 				fLock.Unlock();
630 				// sleep
631 				error = sleeper->Sleep(timeout);
632 				fLock.Lock();
633 				// remove sleeper
634 				info->RemoveSleeper(sleeper);
635 				delete sleeper;
636 			}
637 		}
638 	}
639 	fLock.Unlock();
640 	return (error == B_OK);
641 }
642 
643 // StandardMessages
644 BList*
StandardMessages()645 LaunchContext::StandardMessages()
646 {
647 	if (fStandardMessages.IsEmpty()) {
648 		fStandardMessages.AddItem(new BMessage(MSG_1));
649 		fStandardMessages.AddItem(new BMessage(MSG_2));
650 		fStandardMessages.AddItem(new BMessage(MSG_3));
651 	}
652 	return &fStandardMessages;
653 }
654 
655 // AppInfoAt
656 LaunchContext::AppInfo*
AppInfoAt(int32 index) const657 LaunchContext::AppInfoAt(int32 index) const
658 {
659 	return (AppInfo*)fAppInfos.ItemAt(index);
660 }
661 
662 // AppInfoFor
663 LaunchContext::AppInfo*
AppInfoFor(team_id team) const664 LaunchContext::AppInfoFor(team_id team) const
665 {
666 	for (int32 i = 0; AppInfo *info = AppInfoAt(i); i++) {
667 		if (info->Team() == team)
668 			return info;
669 	}
670 	return NULL;
671 }
672 
673 // CreateAppInfo
674 LaunchContext::AppInfo*
CreateAppInfo(BMessenger messenger)675 LaunchContext::CreateAppInfo(BMessenger messenger)
676 {
677 	return CreateAppInfo(messenger.Team(), &messenger);
678 }
679 
680 // CreateAppInfo
681 LaunchContext::AppInfo*
CreateAppInfo(team_id team,const BMessenger * messenger)682 LaunchContext::CreateAppInfo(team_id team, const BMessenger *messenger)
683 {
684 	AppInfo *info = AppInfoFor(team);
685 	if (!info) {
686 		info = new AppInfo(team);
687 		fAppInfos.AddItem(info);
688 	}
689 	if (messenger && !info->Messenger().IsValid())
690 		info->SetMessenger(*messenger);
691 	return info;
692 }
693 
694 // TerminateApp
695 void
TerminateApp(AppInfo * info)696 LaunchContext::TerminateApp(AppInfo *info)
697 {
698 	if (info)
699 		info->Terminate();
700 }
701 
702 // Terminator
703 int32
Terminator()704 LaunchContext::Terminator()
705 {
706 	bool allGone = false;
707 	while (!allGone) {
708 		allGone = true;
709 		fLock.Lock();
710 		for (int32 i = 0; AppInfo *info = AppInfoAt(i); i++) {
711 			team_info teamInfo;
712 			allGone &= (get_team_info(info->Team(), &teamInfo) != B_OK);
713 		}
714 		fLock.Unlock();
715 		if (!allGone)
716 			snooze(10000);
717 	}
718 	be_app->PostMessage(B_QUIT_REQUESTED, be_app);
719 	return 0;
720 }
721 
722 // AppThreadEntry
723 int32
AppThreadEntry(void *)724 LaunchContext::AppThreadEntry(void *)
725 {
726 	be_app->Lock();
727 	be_app->Run();
728 	return 0;
729 }
730 
731 // TerminatorEntry
732 int32
TerminatorEntry(void * data)733 LaunchContext::TerminatorEntry(void *data)
734 {
735 	return ((LaunchContext*)data)->Terminator();
736 }
737 
738 // FindMessage
739 LaunchContext::Message*
FindMessage(uint32 messageCode)740 LaunchContext::FindMessage(uint32 messageCode)
741 {
742 	BAutolock _lock(fLock);
743 	Message *message = NULL;
744 	AppInfo *info = NULL;
745 	for (int32 i = 0; !message && (info = AppInfoAt(i)) != NULL; i++)
746 		message = info->FindMessage(messageCode);
747 	return message;
748 }
749 
750 // AddSleeper
751 void
AddSleeper(Sleeper * sleeper)752 LaunchContext::AddSleeper(Sleeper *sleeper)
753 {
754 	fSleepers.AddItem(sleeper);
755 }
756 
757 // RemoveSleeper
758 void
RemoveSleeper(Sleeper * sleeper)759 LaunchContext::RemoveSleeper(Sleeper *sleeper)
760 {
761 	fSleepers.RemoveItem(sleeper);
762 }
763 
764 // NotifySleepers
765 void
NotifySleepers(uint32 messageCode)766 LaunchContext::NotifySleepers(uint32 messageCode)
767 {
768 	for (int32 i = 0; Sleeper *sleeper = (Sleeper*)fSleepers.ItemAt(i); i++) {
769 		if (sleeper->MessageCode() == messageCode)
770 			sleeper->WakeUp();
771 	}
772 }
773 
774 
775 ///////////////////
776 // RosterLaunchApp
777 
778 // constructor
RosterLaunchApp(const char * signature)779 RosterLaunchApp::RosterLaunchApp(const char *signature)
780 	: BApplication(signature),
781 	  fLaunchContext(NULL),
782 	  fHandler(NULL)
783 {
784 }
785 
786 // destructor
~RosterLaunchApp()787 RosterLaunchApp::~RosterLaunchApp()
788 {
789 	SetHandler(NULL);
790 }
791 
792 // MessageReceived
793 void
MessageReceived(BMessage * message)794 RosterLaunchApp::MessageReceived(BMessage *message)
795 {
796 	if (fLaunchContext)
797 		fLaunchContext->HandleMessage(message);
798 }
799 
800 // SetLaunchContext
801 void
SetLaunchContext(LaunchContext * context)802 RosterLaunchApp::SetLaunchContext(LaunchContext *context)
803 {
804 	fLaunchContext = context;
805 }
806 
807 // GetLaunchContext
808 LaunchContext *
GetLaunchContext() const809 RosterLaunchApp::GetLaunchContext() const
810 {
811 	return fLaunchContext;
812 }
813 
814 // SetHandler
815 void
SetHandler(BHandler * handler)816 RosterLaunchApp::SetHandler(BHandler *handler)
817 {
818 	Lock();
819 	if (fHandler) {
820 		RemoveHandler(fHandler);
821 		delete fHandler;
822 		fHandler = NULL;
823 	}
824 	if (handler) {
825 		fHandler = handler;
826 		AddHandler(handler);
827 	}
828 	Unlock();
829 }
830 
831 
832 //////////////////////////
833 // RosterBroadcastHandler
834 
835 // constructor
RosterBroadcastHandler()836 RosterBroadcastHandler::RosterBroadcastHandler()
837 {
838 }
839 
840 // MessageReceived
841 void
MessageReceived(BMessage * message)842 RosterBroadcastHandler::MessageReceived(BMessage *message)
843 {
844 	RosterLaunchApp *app = dynamic_cast<RosterLaunchApp*>(be_app);
845 	if (LaunchContext *launchContext = app->GetLaunchContext()) {
846 		message->AddInt32("original what", (int32)message->what);
847 		message->what = MSG_REPLY;
848 		launchContext->HandleMessage(message);
849 	}
850 }
851 
852