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