Added app flags related tests. Fixed some problems: LaunchContext doesn't have a LaunchCaller as member anymore, team = NULL parameter for BRoster::Launch() is now handled gracefully.
git-svn-id: file:///srv/svn/repos/haiku/trunk/current@1370 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -256,6 +256,67 @@ case 13:mimeType is installed, but has no preferred application,
|
|||||||
case 14:installed type mimeType, preferred app, app type not installed,
|
case 14:installed type mimeType, preferred app, app type not installed,
|
||||||
app has signature, app is trash =>
|
app has signature, app is trash =>
|
||||||
Should return B_LAUNCH_FAILED_APP_IN_TRASH.
|
Should return B_LAUNCH_FAILED_APP_IN_TRASH.
|
||||||
|
case 15:installed type mimeType, preferred app, app type not installed,
|
||||||
|
app has signature, team is NULL =>
|
||||||
|
Should return B_OK and set team to the ID of the team running the
|
||||||
|
application's executable. Should install the app type and set the
|
||||||
|
app hint on it.
|
||||||
|
|
||||||
|
case 16:launch the app two times: B_MULTIPLE_LAUNCH | B_ARGV_ONLY =>
|
||||||
|
first app: ArgvReceived(), ReadyToRun(), QuitRequested()
|
||||||
|
second app: ArgvReceived(), ReadyToRun(), QuitRequested()
|
||||||
|
case 17:launch the app two times: B_MULTIPLE_LAUNCH =>
|
||||||
|
first app: {Message,Argv,Refs}Received()*, ReadyToRun(),
|
||||||
|
QuitRequested()
|
||||||
|
second app: {Message,Argv,Refs}Received()*, ReadyToRun(),
|
||||||
|
QuitRequested()
|
||||||
|
case 18:launch the app two times: B_SINGLE_LAUNCH | B_ARGV_ONLY =>
|
||||||
|
first app: ArgvReceived(), ReadyToRun(), QuitRequested()
|
||||||
|
(No second ArgvReceived()!)
|
||||||
|
second app: Launch() fails with B_ALREADY_RUNNING
|
||||||
|
case 19:launch the app two times: B_SINGLE_LAUNCH =>
|
||||||
|
first app: {Message,Argv,Refs}Received()*, ReadyToRun(),
|
||||||
|
{Message,Argv,Refs}Received()*, QuitRequested()
|
||||||
|
second app: Launch() fails with B_ALREADY_RUNNING
|
||||||
|
case 20:launch two apps with the same signature:
|
||||||
|
B_SINGLE_LAUNCH | B_ARGV_ONLY =>
|
||||||
|
first app: ArgvReceived(), ReadyToRun(), QuitRequested()
|
||||||
|
second app: ArgvReceived(), ReadyToRun(), QuitRequested()
|
||||||
|
case 21:launch two apps with the same signature: B_SINGLE_LAUNCH =>
|
||||||
|
first app: {Message,Argv,Refs}Received()*, ReadyToRun(),
|
||||||
|
QuitRequested()
|
||||||
|
second app: {Message,Argv,Refs}Received()*, ReadyToRun(),
|
||||||
|
QuitRequested()
|
||||||
|
case 22:launch the app two times: B_EXCLUSIVE_LAUNCH | B_ARGV_ONLY =>
|
||||||
|
first app: ArgvReceived(), ReadyToRun(), QuitRequested()
|
||||||
|
(No second ArgvReceived()!)
|
||||||
|
second app: Launch() fails with B_ALREADY_RUNNING
|
||||||
|
case 23:launch the app two times: B_EXCLUSIVE_LAUNCH =>
|
||||||
|
first app: {Message,Argv,Refs}Received()*, ReadyToRun(),
|
||||||
|
{Message,Argv,Refs}Received()*, QuitRequested()
|
||||||
|
second app: Launch() fails with B_ALREADY_RUNNING
|
||||||
|
case 24:launch two apps with the same signature:
|
||||||
|
B_EXCLUSIVE_LAUNCH | B_ARGV_ONLY =>
|
||||||
|
first app: ArgvReceived(), ReadyToRun(), QuitRequested()
|
||||||
|
(No second ArgvReceived()!)
|
||||||
|
second app: Launch() fails with B_ALREADY_RUNNING
|
||||||
|
case 25:launch two apps with the same signature: B_EXCLUSIVE_LAUNCH =>
|
||||||
|
first app: {Message,Argv,Refs}Received()*, ReadyToRun(),
|
||||||
|
{Message,Argv,Refs}Received()*, QuitRequested()
|
||||||
|
second app: Launch() fails with B_ALREADY_RUNNING
|
||||||
|
case 26:launch two apps with the same signature:
|
||||||
|
first: B_EXCLUSIVE_LAUNCH,
|
||||||
|
second: B_EXCLUSIVE_LAUNCH | B_ARGV_ONLY =>
|
||||||
|
first app: {Message,Argv,Refs}Received()*, ReadyToRun(),
|
||||||
|
QuitRequested()
|
||||||
|
second app: Launch() fails with B_ALREADY_RUNNING
|
||||||
|
case 27:launch two apps with the same signature:
|
||||||
|
first: B_EXCLUSIVE_LAUNCH | B_ARGV_ONLY,
|
||||||
|
second: B_EXCLUSIVE_LAUNCH =>
|
||||||
|
first app: ArgvReceived(), ReadyToRun(), QuitRequested()
|
||||||
|
(No second ArgvReceived()!)
|
||||||
|
second app: Launch() fails with B_ALREADY_RUNNING
|
||||||
|
|
||||||
|
|
||||||
status_t Launch(const char *mimeType, BMessage *initialMsg,
|
status_t Launch(const char *mimeType, BMessage *initialMsg,
|
||||||
team_id *appTeam) const
|
team_id *appTeam) const
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -29,6 +29,40 @@ public:
|
|||||||
bigtime_t when;
|
bigtime_t when;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Sleeper
|
||||||
|
class LaunchContext::Sleeper {
|
||||||
|
public:
|
||||||
|
Sleeper() : fMessageCode(0), fSemaphore(-1) {}
|
||||||
|
|
||||||
|
~Sleeper()
|
||||||
|
{
|
||||||
|
delete_sem(fSemaphore);
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t Init(uint32 messageCode)
|
||||||
|
{
|
||||||
|
fMessageCode = messageCode;
|
||||||
|
fSemaphore = create_sem(0, "sleeper sem");
|
||||||
|
return (fSemaphore >= 0 ? B_OK : fSemaphore);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 MessageCode() const { return fMessageCode; }
|
||||||
|
|
||||||
|
status_t Sleep(bigtime_t timeout = B_INFINITE_TIMEOUT)
|
||||||
|
{
|
||||||
|
return acquire_sem_etc(fSemaphore, 1, B_RELATIVE_TIMEOUT, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t WakeUp()
|
||||||
|
{
|
||||||
|
return release_sem(fSemaphore);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint32 fMessageCode;
|
||||||
|
sem_id fSemaphore;
|
||||||
|
};
|
||||||
|
|
||||||
// AppInfo
|
// AppInfo
|
||||||
class LaunchContext::AppInfo {
|
class LaunchContext::AppInfo {
|
||||||
public:
|
public:
|
||||||
@@ -76,6 +110,7 @@ public:
|
|||||||
message->message = _message;
|
message->message = _message;
|
||||||
message->when = system_time();
|
message->when = system_time();
|
||||||
fMessages.AddItem(message);
|
fMessages.AddItem(message);
|
||||||
|
NotifySleepers(_message.what);
|
||||||
}
|
}
|
||||||
|
|
||||||
LaunchContext::Message *RemoveMessage(int32 index)
|
LaunchContext::Message *RemoveMessage(int32 index)
|
||||||
@@ -88,17 +123,49 @@ public:
|
|||||||
return (LaunchContext::Message*)fMessages.ItemAt(index);
|
return (LaunchContext::Message*)fMessages.ItemAt(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LaunchContext::Message *FindMessage(uint32 messageCode,
|
||||||
|
int32 startIndex = 0) const
|
||||||
|
{
|
||||||
|
LaunchContext::Message *message = NULL;
|
||||||
|
for (int32 i = startIndex; (message = MessageAt(i)) != NULL; i++) {
|
||||||
|
if (message->message.what == messageCode)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddSleeper(Sleeper *sleeper)
|
||||||
|
{
|
||||||
|
fSleepers.AddItem(sleeper);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RemoveSleeper(Sleeper *sleeper)
|
||||||
|
{
|
||||||
|
fSleepers.RemoveItem(sleeper);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NotifySleepers(uint32 messageCode)
|
||||||
|
{
|
||||||
|
for (int32 i = 0;
|
||||||
|
Sleeper *sleeper = (Sleeper*)fSleepers.ItemAt(i);
|
||||||
|
i++) {
|
||||||
|
if (sleeper->MessageCode() == messageCode)
|
||||||
|
sleeper->WakeUp();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
team_id fTeam;
|
team_id fTeam;
|
||||||
BMessenger fMessenger;
|
BMessenger fMessenger;
|
||||||
BList fMessages;
|
BList fMessages;
|
||||||
bool fTerminating;
|
bool fTerminating;
|
||||||
|
BList fSleepers;
|
||||||
};
|
};
|
||||||
|
|
||||||
// constructor
|
// constructor
|
||||||
LaunchContext::LaunchContext(LaunchCaller &caller)
|
LaunchContext::LaunchContext()
|
||||||
: fCaller(caller),
|
: fAppInfos(),
|
||||||
fAppInfos(),
|
fSleepers(),
|
||||||
fLock(),
|
fLock(),
|
||||||
fAppThread(B_ERROR),
|
fAppThread(B_ERROR),
|
||||||
fTerminator(B_ERROR),
|
fTerminator(B_ERROR),
|
||||||
@@ -133,7 +200,8 @@ LaunchContext::~LaunchContext()
|
|||||||
|
|
||||||
// ()
|
// ()
|
||||||
status_t
|
status_t
|
||||||
LaunchContext::operator()(const char *type, team_id *team)
|
LaunchContext::operator()(LaunchCaller &caller, const char *type,
|
||||||
|
team_id *team)
|
||||||
{
|
{
|
||||||
BMessage message1(MSG_1);
|
BMessage message1(MSG_1);
|
||||||
BMessage message2(MSG_2);
|
BMessage message2(MSG_2);
|
||||||
@@ -142,28 +210,20 @@ LaunchContext::operator()(const char *type, team_id *team)
|
|||||||
messages.AddItem(&message1);
|
messages.AddItem(&message1);
|
||||||
messages.AddItem(&message2);
|
messages.AddItem(&message2);
|
||||||
messages.AddItem(&message3);
|
messages.AddItem(&message3);
|
||||||
return (*this)(type, &messages, kStandardArgc, kStandardArgv, team);
|
return (*this)(caller, type, &messages, kStandardArgc, kStandardArgv,
|
||||||
|
team);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ()
|
// ()
|
||||||
status_t
|
status_t
|
||||||
LaunchContext::operator()(const char *type, BList *messages, int32 argc,
|
LaunchContext::operator()(LaunchCaller &caller, const char *type,
|
||||||
const char **argv, team_id *team)
|
BList *messages, int32 argc, const char **argv,
|
||||||
|
team_id *team)
|
||||||
{
|
{
|
||||||
BAutolock _lock(fLock);
|
BAutolock _lock(fLock);
|
||||||
status_t result = fCaller(type, messages, argc, argv, team);
|
status_t result = caller(type, messages, argc, argv, team);
|
||||||
if (result == B_OK) {
|
if (result == B_OK && team)
|
||||||
if (team)
|
CreateAppInfo(*team);
|
||||||
CreateAppInfo(*team);
|
|
||||||
else {
|
|
||||||
// Note: Here's a race condition. If Terminate() is called, before
|
|
||||||
// we've received the first message from the test app, then
|
|
||||||
// there's a good chance that we quit the application before
|
|
||||||
// having received any message (or at least not all messages)
|
|
||||||
// from the test app. We wait some time to minimize the chance...
|
|
||||||
snooze(100000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,6 +233,14 @@ LaunchContext::HandleMessage(BMessage *message)
|
|||||||
{
|
{
|
||||||
//printf("LaunchContext::HandleMessage(%6ld: %.4s)\n",
|
//printf("LaunchContext::HandleMessage(%6ld: %.4s)\n",
|
||||||
//message->ReturnAddress().Team(), (char*)&message->what);
|
//message->ReturnAddress().Team(), (char*)&message->what);
|
||||||
|
//if (message->what == MSG_MESSAGE_RECEIVED) {
|
||||||
|
// BMessage sentMessage;
|
||||||
|
// message->FindMessage("message", &sentMessage);
|
||||||
|
// team_id sender = -1;
|
||||||
|
// message->FindInt32("sender", &sender);
|
||||||
|
// printf(" <- %6ld: %.4s\n", sender, (char*)&sentMessage.what);
|
||||||
|
//}
|
||||||
|
|
||||||
BAutolock _lock(fLock);
|
BAutolock _lock(fLock);
|
||||||
switch (message->what) {
|
switch (message->what) {
|
||||||
case MSG_STARTED:
|
case MSG_STARTED:
|
||||||
@@ -184,10 +252,20 @@ LaunchContext::HandleMessage(BMessage *message)
|
|||||||
case MSG_READY_TO_RUN:
|
case MSG_READY_TO_RUN:
|
||||||
{
|
{
|
||||||
BMessenger messenger = message->ReturnAddress();
|
BMessenger messenger = message->ReturnAddress();
|
||||||
AppInfo *info = CreateAppInfo(messenger);
|
// add the message to the respective team's message list
|
||||||
info->AddMessage(*message);
|
// Note: catch messages that have not been sent by us or the
|
||||||
if (fTerminating)
|
// remote team. The R5 registrar seems to send a B_REPLY message
|
||||||
TerminateApp(info);
|
// sometimes.
|
||||||
|
team_id sender = -1;
|
||||||
|
if (message->FindInt32("sender", &sender) != B_OK
|
||||||
|
|| sender == be_app->Team()
|
||||||
|
|| sender == messenger.Team()) {
|
||||||
|
AppInfo *info = CreateAppInfo(messenger);
|
||||||
|
info->AddMessage(*message);
|
||||||
|
if (fTerminating)
|
||||||
|
TerminateApp(info);
|
||||||
|
}
|
||||||
|
NotifySleepers(message->what);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -252,7 +330,8 @@ LaunchContext::NextMessageFrom(team_id team, int32 &cookie, bigtime_t *time)
|
|||||||
|
|
||||||
// CheckNextMessage
|
// CheckNextMessage
|
||||||
bool
|
bool
|
||||||
LaunchContext::CheckNextMessage(team_id team, int32 &cookie, uint32 what)
|
LaunchContext::CheckNextMessage(LaunchCaller &caller, team_id team,
|
||||||
|
int32 &cookie, uint32 what)
|
||||||
{
|
{
|
||||||
BMessage *message = NextMessageFrom(team, cookie);
|
BMessage *message = NextMessageFrom(team, cookie);
|
||||||
return (message && message->what == what);
|
return (message && message->what == what);
|
||||||
@@ -260,12 +339,13 @@ LaunchContext::CheckNextMessage(team_id team, int32 &cookie, uint32 what)
|
|||||||
|
|
||||||
// CheckArgvMessage
|
// CheckArgvMessage
|
||||||
bool
|
bool
|
||||||
LaunchContext::CheckArgvMessage(team_id team, int32 &cookie,
|
LaunchContext::CheckArgvMessage(LaunchCaller &caller, team_id team,
|
||||||
const entry_ref *appRef, bool useRef)
|
int32 &cookie, const entry_ref *appRef,
|
||||||
|
bool useRef)
|
||||||
{
|
{
|
||||||
bool result = true;
|
bool result = true;
|
||||||
if (fCaller.SupportsArgv()) {
|
if (caller.SupportsArgv()) {
|
||||||
result = CheckArgvMessage(team, cookie, appRef, kStandardArgc,
|
result = CheckArgvMessage(caller, team, cookie, appRef, kStandardArgc,
|
||||||
kStandardArgv, useRef);
|
kStandardArgv, useRef);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@@ -273,18 +353,18 @@ LaunchContext::CheckArgvMessage(team_id team, int32 &cookie,
|
|||||||
|
|
||||||
// CheckArgvMessage
|
// CheckArgvMessage
|
||||||
bool
|
bool
|
||||||
LaunchContext::CheckArgvMessage(team_id team, int32 &cookie,
|
LaunchContext::CheckArgvMessage(LaunchCaller &caller, team_id team,
|
||||||
const entry_ref *appRef, int32 argc,
|
int32 &cookie, const entry_ref *appRef,
|
||||||
const char **argv, bool useRef)
|
int32 argc, const char **argv, bool useRef)
|
||||||
{
|
{
|
||||||
const entry_ref *ref = (useRef ? fCaller.Ref() : NULL);
|
const entry_ref *ref = (useRef ? caller.Ref() : NULL);
|
||||||
return CheckArgvMessage(team, cookie, appRef, ref , argc, argv);
|
return CheckArgvMessage(caller, team, cookie, appRef, ref , argc, argv);
|
||||||
}
|
}
|
||||||
|
|
||||||
// CheckArgvMessage
|
// CheckArgvMessage
|
||||||
bool
|
bool
|
||||||
LaunchContext::CheckArgvMessage(team_id team, int32 &cookie,
|
LaunchContext::CheckArgvMessage(LaunchCaller &caller, team_id team,
|
||||||
const entry_ref *appRef,
|
int32 &cookie, const entry_ref *appRef,
|
||||||
const entry_ref *ref , int32 argc,
|
const entry_ref *ref , int32 argc,
|
||||||
const char **argv)
|
const char **argv)
|
||||||
{
|
{
|
||||||
@@ -330,62 +410,36 @@ printf("app paths differ: `%s' vs `%s'\n", arg, path.Path());
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveStandardArgvMessage
|
|
||||||
bool
|
|
||||||
LaunchContext::RemoveStandardArgvMessage(team_id team, const entry_ref *appRef)
|
|
||||||
{
|
|
||||||
return RemoveArgvMessage(team, appRef, kStandardArgc, kStandardArgv);
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoveArgvMessage
|
|
||||||
bool
|
|
||||||
LaunchContext::RemoveArgvMessage(team_id team, const entry_ref *appRef,
|
|
||||||
int32 argc, const char **argv)
|
|
||||||
{
|
|
||||||
BAutolock _lock(fLock);
|
|
||||||
bool result = true;
|
|
||||||
if (fCaller.SupportsArgv()) {
|
|
||||||
result = false;
|
|
||||||
int32 cookie = 0;
|
|
||||||
while (BMessage *message = NextMessageFrom(team, cookie)) {
|
|
||||||
if (message->what == MSG_ARGV_RECEIVED) {
|
|
||||||
int32 index = --cookie;
|
|
||||||
result = CheckArgvMessage(team, cookie, appRef, argc, argv);
|
|
||||||
delete AppInfoFor(team)->RemoveMessage(index);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// CheckMessageMessages
|
// CheckMessageMessages
|
||||||
bool
|
bool
|
||||||
LaunchContext::CheckMessageMessages(team_id team, int32 &cookie)
|
LaunchContext::CheckMessageMessages(LaunchCaller &caller, team_id team,
|
||||||
|
int32 &cookie)
|
||||||
{
|
{
|
||||||
BAutolock _lock(fLock);
|
BAutolock _lock(fLock);
|
||||||
bool result = true;
|
bool result = true;
|
||||||
for (int32 i = 0; i < 3; i++)
|
for (int32 i = 0; i < 3; i++)
|
||||||
result &= CheckMessageMessage(team, cookie, i);
|
result &= CheckMessageMessage(caller, team, cookie, i);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// CheckMessageMessage
|
// CheckMessageMessage
|
||||||
bool
|
bool
|
||||||
LaunchContext::CheckMessageMessage(team_id team, int32 &cookie, int32 index)
|
LaunchContext::CheckMessageMessage(LaunchCaller &caller, team_id team,
|
||||||
|
int32 &cookie, int32 index)
|
||||||
{
|
{
|
||||||
bool result = true;
|
bool result = true;
|
||||||
if (fCaller.SupportsMessages() > index && index < 3) {
|
if (caller.SupportsMessages() > index && index < 3) {
|
||||||
uint32 commands[] = { MSG_1, MSG_2, MSG_3 };
|
uint32 commands[] = { MSG_1, MSG_2, MSG_3 };
|
||||||
BMessage message(commands[index]);
|
BMessage message(commands[index]);
|
||||||
result = CheckMessageMessage(team, cookie, &message);
|
result = CheckMessageMessage(caller, team, cookie, &message);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// CheckMessageMessage
|
// CheckMessageMessage
|
||||||
bool
|
bool
|
||||||
LaunchContext::CheckMessageMessage(team_id team, int32 &cookie,
|
LaunchContext::CheckMessageMessage(LaunchCaller &caller, team_id team,
|
||||||
|
int32 &cookie,
|
||||||
const BMessage *expectedMessage)
|
const BMessage *expectedMessage)
|
||||||
{
|
{
|
||||||
BMessage *message = NextMessageFrom(team, cookie);
|
BMessage *message = NextMessageFrom(team, cookie);
|
||||||
@@ -400,18 +454,20 @@ LaunchContext::CheckMessageMessage(team_id team, int32 &cookie,
|
|||||||
|
|
||||||
// CheckRefsMessage
|
// CheckRefsMessage
|
||||||
bool
|
bool
|
||||||
LaunchContext::CheckRefsMessage(team_id team, int32 &cookie)
|
LaunchContext::CheckRefsMessage(LaunchCaller &caller, team_id team,
|
||||||
|
int32 &cookie)
|
||||||
{
|
{
|
||||||
bool result = true;
|
bool result = true;
|
||||||
if (fCaller.SupportsRefs())
|
if (caller.SupportsRefs())
|
||||||
result = CheckRefsMessage(team, cookie, fCaller.Ref());
|
result = CheckRefsMessage(caller, team, cookie, caller.Ref());
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// CheckRefsMessage
|
// CheckRefsMessage
|
||||||
bool
|
bool
|
||||||
LaunchContext::CheckRefsMessage(team_id team, int32 &cookie,
|
LaunchContext::CheckRefsMessage(LaunchCaller &caller, team_id team,
|
||||||
const entry_ref *refs, int32 count)
|
int32 &cookie, const entry_ref *refs,
|
||||||
|
int32 count)
|
||||||
{
|
{
|
||||||
BMessage *message = NextMessageFrom(team, cookie);
|
BMessage *message = NextMessageFrom(team, cookie);
|
||||||
bool result = (message && message->what == MSG_REFS_RECEIVED);
|
bool result = (message && message->what == MSG_REFS_RECEIVED);
|
||||||
@@ -425,25 +481,60 @@ LaunchContext::CheckRefsMessage(team_id team, int32 &cookie,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveRefsMessage
|
// WaitForMessage
|
||||||
bool
|
bool
|
||||||
LaunchContext::RemoveRefsMessage(team_id team)
|
LaunchContext::WaitForMessage(uint32 messageCode, bool fromNow,
|
||||||
|
bigtime_t timeout)
|
||||||
{
|
{
|
||||||
BAutolock _lock(fLock);
|
status_t error = B_ERROR;
|
||||||
bool result = true;
|
fLock.Lock();
|
||||||
if (fCaller.SupportsRefs()) {
|
error = B_OK;
|
||||||
result = false;
|
if (fromNow || !FindMessage(messageCode)) {
|
||||||
int32 cookie = 0;
|
// add sleeper
|
||||||
while (BMessage *message = NextMessageFrom(team, cookie)) {
|
Sleeper *sleeper = new Sleeper;
|
||||||
if (message->what == MSG_REFS_RECEIVED) {
|
error = sleeper->Init(messageCode);
|
||||||
int32 index = --cookie;
|
if (error == B_OK) {
|
||||||
result = CheckRefsMessage(team, cookie);
|
AddSleeper(sleeper);
|
||||||
delete AppInfoFor(team)->RemoveMessage(index);
|
fLock.Unlock();
|
||||||
break;
|
// sleep
|
||||||
|
error = sleeper->Sleep(timeout);
|
||||||
|
fLock.Lock();
|
||||||
|
// remove sleeper
|
||||||
|
RemoveSleeper(sleeper);
|
||||||
|
delete sleeper;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fLock.Unlock();
|
||||||
|
return (error == B_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
// WaitForMessage
|
||||||
|
bool
|
||||||
|
LaunchContext::WaitForMessage(team_id team, uint32 messageCode, bool fromNow,
|
||||||
|
bigtime_t timeout)
|
||||||
|
{
|
||||||
|
status_t error = B_ERROR;
|
||||||
|
fLock.Lock();
|
||||||
|
if (AppInfo *info = AppInfoFor(team)) {
|
||||||
|
error = B_OK;
|
||||||
|
if (fromNow || !info->FindMessage(messageCode)) {
|
||||||
|
// add sleeper
|
||||||
|
Sleeper *sleeper = new Sleeper;
|
||||||
|
error = sleeper->Init(messageCode);
|
||||||
|
if (error == B_OK) {
|
||||||
|
info->AddSleeper(sleeper);
|
||||||
|
fLock.Unlock();
|
||||||
|
// sleep
|
||||||
|
error = sleeper->Sleep(timeout);
|
||||||
|
fLock.Lock();
|
||||||
|
// remove sleeper
|
||||||
|
info->RemoveSleeper(sleeper);
|
||||||
|
delete sleeper;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
fLock.Unlock();
|
||||||
|
return (error == B_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
// StandardMessages
|
// StandardMessages
|
||||||
@@ -541,6 +632,42 @@ LaunchContext::TerminatorEntry(void *data)
|
|||||||
return ((LaunchContext*)data)->Terminator();
|
return ((LaunchContext*)data)->Terminator();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FindMessage
|
||||||
|
LaunchContext::Message*
|
||||||
|
LaunchContext::FindMessage(uint32 messageCode)
|
||||||
|
{
|
||||||
|
BAutolock _lock(fLock);
|
||||||
|
Message *message = NULL;
|
||||||
|
AppInfo *info = NULL;
|
||||||
|
for (int32 i = 0; !message && (info = AppInfoAt(i)) != NULL; i++)
|
||||||
|
message = info->FindMessage(messageCode);
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddSleeper
|
||||||
|
void
|
||||||
|
LaunchContext::AddSleeper(Sleeper *sleeper)
|
||||||
|
{
|
||||||
|
fSleepers.AddItem(sleeper);
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveSleeper
|
||||||
|
void
|
||||||
|
LaunchContext::RemoveSleeper(Sleeper *sleeper)
|
||||||
|
{
|
||||||
|
fSleepers.RemoveItem(sleeper);
|
||||||
|
}
|
||||||
|
|
||||||
|
// NotifySleepers
|
||||||
|
void
|
||||||
|
LaunchContext::NotifySleepers(uint32 messageCode)
|
||||||
|
{
|
||||||
|
for (int32 i = 0; Sleeper *sleeper = (Sleeper*)fSleepers.ItemAt(i); i++) {
|
||||||
|
if (sleeper->MessageCode() == messageCode)
|
||||||
|
sleeper->WakeUp();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
///////////////////
|
///////////////////
|
||||||
// RosterLaunchApp
|
// RosterLaunchApp
|
||||||
|
|||||||
@@ -18,23 +18,40 @@ enum {
|
|||||||
// LaunchCaller
|
// LaunchCaller
|
||||||
class LaunchCaller {
|
class LaunchCaller {
|
||||||
public:
|
public:
|
||||||
|
LaunchCaller() : fNext(NULL) {}
|
||||||
|
virtual ~LaunchCaller() { if (fNext) delete fNext;}
|
||||||
|
|
||||||
virtual status_t operator()(const char *type, BList *messages, int32 argc,
|
virtual status_t operator()(const char *type, BList *messages, int32 argc,
|
||||||
const char **argv, team_id *team) = 0;
|
const char **argv, team_id *team) = 0;
|
||||||
virtual int32 SupportsMessages() const { return 1; }
|
virtual int32 SupportsMessages() const { return 1; }
|
||||||
virtual bool SupportsArgv() const { return SupportsMessages() == 0; }
|
virtual bool SupportsArgv() const { return SupportsMessages() == 0; }
|
||||||
virtual bool SupportsRefs() const { return false; }
|
virtual bool SupportsRefs() const { return false; }
|
||||||
virtual const entry_ref *Ref() const { return NULL; }
|
virtual const entry_ref *Ref() const { return NULL; }
|
||||||
|
|
||||||
|
virtual LaunchCaller &Clone()
|
||||||
|
{
|
||||||
|
LaunchCaller *newCaller = CloneInternal();
|
||||||
|
newCaller->fNext = fNext;
|
||||||
|
fNext = newCaller;
|
||||||
|
return *newCaller;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual LaunchCaller *CloneInternal() = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
LaunchCaller *fNext;
|
||||||
};
|
};
|
||||||
|
|
||||||
// LaunchContext
|
// LaunchContext
|
||||||
class LaunchContext {
|
class LaunchContext {
|
||||||
public:
|
public:
|
||||||
LaunchContext(LaunchCaller &caller);
|
LaunchContext();
|
||||||
~LaunchContext();
|
~LaunchContext();
|
||||||
|
|
||||||
status_t operator()(const char *type, team_id *team);
|
status_t operator()(LaunchCaller &caller, const char *type, team_id *team);
|
||||||
status_t operator()(const char *type, BList *messages, int32 argc,
|
status_t operator()(LaunchCaller &caller, const char *type,
|
||||||
const char **argv, team_id *team);
|
BList *messages, int32 argc, const char **argv,
|
||||||
|
team_id *team);
|
||||||
|
|
||||||
void HandleMessage(BMessage *message);
|
void HandleMessage(BMessage *message);
|
||||||
|
|
||||||
@@ -44,24 +61,30 @@ public:
|
|||||||
|
|
||||||
BMessage *NextMessageFrom(team_id team, int32 &cookie,
|
BMessage *NextMessageFrom(team_id team, int32 &cookie,
|
||||||
bigtime_t *time = NULL);
|
bigtime_t *time = NULL);
|
||||||
bool CheckNextMessage(team_id team, int32 &cookie, uint32 what);
|
bool CheckNextMessage(LaunchCaller &caller, team_id team, int32 &cookie,
|
||||||
bool CheckArgvMessage(team_id team, int32 &cookie,
|
uint32 what);
|
||||||
|
bool CheckArgvMessage(LaunchCaller &caller, team_id team, int32 &cookie,
|
||||||
const entry_ref *appRef, bool useRef = true);
|
const entry_ref *appRef, bool useRef = true);
|
||||||
bool CheckArgvMessage(team_id team, int32 &cookie, const entry_ref *appRef,
|
bool CheckArgvMessage(LaunchCaller &caller, team_id team, int32 &cookie,
|
||||||
|
const entry_ref *appRef,
|
||||||
int32 argc, const char **argv, bool useRef = true);
|
int32 argc, const char **argv, bool useRef = true);
|
||||||
bool CheckArgvMessage(team_id team, int32 &cookie, const entry_ref *appRef,
|
bool CheckArgvMessage(LaunchCaller &caller, team_id team, int32 &cookie,
|
||||||
const entry_ref *ref, int32 argc, const char **argv);
|
const entry_ref *appRef, const entry_ref *ref,
|
||||||
bool RemoveStandardArgvMessage(team_id team, const entry_ref *appRef);
|
int32 argc, const char **argv);
|
||||||
bool RemoveArgvMessage(team_id team, const entry_ref *appRef, int32 argc,
|
bool CheckMessageMessages(LaunchCaller &caller, team_id team,
|
||||||
const char **argv);
|
int32 &cookie);
|
||||||
bool CheckMessageMessages(team_id team, int32 &cookie);
|
bool CheckMessageMessage(LaunchCaller &caller, team_id team, int32 &cookie,
|
||||||
bool CheckMessageMessage(team_id team, int32 &cookie, int32 index);
|
int32 index);
|
||||||
bool CheckMessageMessage(team_id team, int32 &cookie,
|
bool CheckMessageMessage(LaunchCaller &caller, team_id team, int32 &cookie,
|
||||||
const BMessage *message);
|
const BMessage *message);
|
||||||
bool CheckRefsMessage(team_id team, int32 &cookie);
|
bool CheckRefsMessage(LaunchCaller &caller, team_id team, int32 &cookie);
|
||||||
bool CheckRefsMessage(team_id team, int32 &cookie, const entry_ref *refs,
|
bool CheckRefsMessage(LaunchCaller &caller, team_id team, int32 &cookie,
|
||||||
int32 count = 1);
|
const entry_ref *refs, int32 count = 1);
|
||||||
bool RemoveRefsMessage(team_id team);
|
|
||||||
|
bool WaitForMessage(uint32 messageCode, bool fromNow = false,
|
||||||
|
bigtime_t timeout = B_INFINITE_TIMEOUT);
|
||||||
|
bool WaitForMessage(team_id team, uint32 messageCode, bool fromNow = false,
|
||||||
|
bigtime_t timeout = B_INFINITE_TIMEOUT);
|
||||||
|
|
||||||
BList *StandardMessages();
|
BList *StandardMessages();
|
||||||
|
|
||||||
@@ -71,6 +94,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
class Message;
|
class Message;
|
||||||
|
class Sleeper;
|
||||||
class AppInfo;
|
class AppInfo;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -80,14 +104,19 @@ private:
|
|||||||
AppInfo *CreateAppInfo(BMessenger messenger);
|
AppInfo *CreateAppInfo(BMessenger messenger);
|
||||||
void TerminateApp(AppInfo *info);
|
void TerminateApp(AppInfo *info);
|
||||||
|
|
||||||
|
Message *FindMessage(uint32 messageCode);
|
||||||
|
void AddSleeper(Sleeper *sleeper);
|
||||||
|
void RemoveSleeper(Sleeper *sleeper);
|
||||||
|
void NotifySleepers(uint32 messageCode);
|
||||||
|
|
||||||
int32 Terminator();
|
int32 Terminator();
|
||||||
|
|
||||||
static int32 AppThreadEntry(void *data);
|
static int32 AppThreadEntry(void *data);
|
||||||
static int32 TerminatorEntry(void *data);
|
static int32 TerminatorEntry(void *data);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
LaunchCaller &fCaller;
|
|
||||||
BList fAppInfos;
|
BList fAppInfos;
|
||||||
|
BList fSleepers;
|
||||||
mutable BLocker fLock;
|
mutable BLocker fLock;
|
||||||
thread_id fAppThread;
|
thread_id fAppThread;
|
||||||
thread_id fTerminator;
|
thread_id fTerminator;
|
||||||
|
|||||||
Reference in New Issue
Block a user