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:
Ingo Weinhold
2002-10-04 18:00:22 +00:00
parent 04e2ed41e5
commit 48bf189f58
4 changed files with 1281 additions and 400 deletions
+61
View File
@@ -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,
app has signature, app is 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,
team_id *appTeam) const
File diff suppressed because it is too large Load Diff
+217 -90
View File
@@ -29,6 +29,40 @@ public:
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
class LaunchContext::AppInfo {
public:
@@ -76,6 +110,7 @@ public:
message->message = _message;
message->when = system_time();
fMessages.AddItem(message);
NotifySleepers(_message.what);
}
LaunchContext::Message *RemoveMessage(int32 index)
@@ -88,17 +123,49 @@ public:
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:
team_id fTeam;
BMessenger fMessenger;
BList fMessages;
bool fTerminating;
BList fSleepers;
};
// constructor
LaunchContext::LaunchContext(LaunchCaller &caller)
: fCaller(caller),
fAppInfos(),
LaunchContext::LaunchContext()
: fAppInfos(),
fSleepers(),
fLock(),
fAppThread(B_ERROR),
fTerminator(B_ERROR),
@@ -133,7 +200,8 @@ LaunchContext::~LaunchContext()
// ()
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 message2(MSG_2);
@@ -142,28 +210,20 @@ LaunchContext::operator()(const char *type, team_id *team)
messages.AddItem(&message1);
messages.AddItem(&message2);
messages.AddItem(&message3);
return (*this)(type, &messages, kStandardArgc, kStandardArgv, team);
return (*this)(caller, type, &messages, kStandardArgc, kStandardArgv,
team);
}
// ()
status_t
LaunchContext::operator()(const char *type, BList *messages, int32 argc,
const char **argv, team_id *team)
LaunchContext::operator()(LaunchCaller &caller, const char *type,
BList *messages, int32 argc, const char **argv,
team_id *team)
{
BAutolock _lock(fLock);
status_t result = fCaller(type, messages, argc, argv, team);
if (result == B_OK) {
if (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);
}
}
status_t result = caller(type, messages, argc, argv, team);
if (result == B_OK && team)
CreateAppInfo(*team);
return result;
}
@@ -173,6 +233,14 @@ LaunchContext::HandleMessage(BMessage *message)
{
//printf("LaunchContext::HandleMessage(%6ld: %.4s)\n",
//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);
switch (message->what) {
case MSG_STARTED:
@@ -184,10 +252,20 @@ LaunchContext::HandleMessage(BMessage *message)
case MSG_READY_TO_RUN:
{
BMessenger messenger = message->ReturnAddress();
AppInfo *info = CreateAppInfo(messenger);
info->AddMessage(*message);
if (fTerminating)
TerminateApp(info);
// add the message to the respective team's message list
// Note: catch messages that have not been sent by us or the
// remote team. The R5 registrar seems to send a B_REPLY message
// 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;
}
default:
@@ -252,7 +330,8 @@ LaunchContext::NextMessageFrom(team_id team, int32 &cookie, bigtime_t *time)
// CheckNextMessage
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);
return (message && message->what == what);
@@ -260,12 +339,13 @@ LaunchContext::CheckNextMessage(team_id team, int32 &cookie, uint32 what)
// CheckArgvMessage
bool
LaunchContext::CheckArgvMessage(team_id team, int32 &cookie,
const entry_ref *appRef, bool useRef)
LaunchContext::CheckArgvMessage(LaunchCaller &caller, team_id team,
int32 &cookie, const entry_ref *appRef,
bool useRef)
{
bool result = true;
if (fCaller.SupportsArgv()) {
result = CheckArgvMessage(team, cookie, appRef, kStandardArgc,
if (caller.SupportsArgv()) {
result = CheckArgvMessage(caller, team, cookie, appRef, kStandardArgc,
kStandardArgv, useRef);
}
return result;
@@ -273,18 +353,18 @@ LaunchContext::CheckArgvMessage(team_id team, int32 &cookie,
// CheckArgvMessage
bool
LaunchContext::CheckArgvMessage(team_id team, int32 &cookie,
const entry_ref *appRef, int32 argc,
const char **argv, bool useRef)
LaunchContext::CheckArgvMessage(LaunchCaller &caller, team_id team,
int32 &cookie, const entry_ref *appRef,
int32 argc, const char **argv, bool useRef)
{
const entry_ref *ref = (useRef ? fCaller.Ref() : NULL);
return CheckArgvMessage(team, cookie, appRef, ref , argc, argv);
const entry_ref *ref = (useRef ? caller.Ref() : NULL);
return CheckArgvMessage(caller, team, cookie, appRef, ref , argc, argv);
}
// CheckArgvMessage
bool
LaunchContext::CheckArgvMessage(team_id team, int32 &cookie,
const entry_ref *appRef,
LaunchContext::CheckArgvMessage(LaunchCaller &caller, team_id team,
int32 &cookie, const entry_ref *appRef,
const entry_ref *ref , int32 argc,
const char **argv)
{
@@ -330,62 +410,36 @@ printf("app paths differ: `%s' vs `%s'\n", arg, path.Path());
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
bool
LaunchContext::CheckMessageMessages(team_id team, int32 &cookie)
LaunchContext::CheckMessageMessages(LaunchCaller &caller, team_id team,
int32 &cookie)
{
BAutolock _lock(fLock);
bool result = true;
for (int32 i = 0; i < 3; i++)
result &= CheckMessageMessage(team, cookie, i);
result &= CheckMessageMessage(caller, team, cookie, i);
return result;
}
// CheckMessageMessage
bool
LaunchContext::CheckMessageMessage(team_id team, int32 &cookie, int32 index)
LaunchContext::CheckMessageMessage(LaunchCaller &caller, team_id team,
int32 &cookie, int32 index)
{
bool result = true;
if (fCaller.SupportsMessages() > index && index < 3) {
if (caller.SupportsMessages() > index && index < 3) {
uint32 commands[] = { MSG_1, MSG_2, MSG_3 };
BMessage message(commands[index]);
result = CheckMessageMessage(team, cookie, &message);
result = CheckMessageMessage(caller, team, cookie, &message);
}
return result;
}
// CheckMessageMessage
bool
LaunchContext::CheckMessageMessage(team_id team, int32 &cookie,
LaunchContext::CheckMessageMessage(LaunchCaller &caller, team_id team,
int32 &cookie,
const BMessage *expectedMessage)
{
BMessage *message = NextMessageFrom(team, cookie);
@@ -400,18 +454,20 @@ LaunchContext::CheckMessageMessage(team_id team, int32 &cookie,
// CheckRefsMessage
bool
LaunchContext::CheckRefsMessage(team_id team, int32 &cookie)
LaunchContext::CheckRefsMessage(LaunchCaller &caller, team_id team,
int32 &cookie)
{
bool result = true;
if (fCaller.SupportsRefs())
result = CheckRefsMessage(team, cookie, fCaller.Ref());
if (caller.SupportsRefs())
result = CheckRefsMessage(caller, team, cookie, caller.Ref());
return result;
}
// CheckRefsMessage
bool
LaunchContext::CheckRefsMessage(team_id team, int32 &cookie,
const entry_ref *refs, int32 count)
LaunchContext::CheckRefsMessage(LaunchCaller &caller, team_id team,
int32 &cookie, const entry_ref *refs,
int32 count)
{
BMessage *message = NextMessageFrom(team, cookie);
bool result = (message && message->what == MSG_REFS_RECEIVED);
@@ -425,25 +481,60 @@ LaunchContext::CheckRefsMessage(team_id team, int32 &cookie,
return result;
}
// RemoveRefsMessage
// WaitForMessage
bool
LaunchContext::RemoveRefsMessage(team_id team)
LaunchContext::WaitForMessage(uint32 messageCode, bool fromNow,
bigtime_t timeout)
{
BAutolock _lock(fLock);
bool result = true;
if (fCaller.SupportsRefs()) {
result = false;
int32 cookie = 0;
while (BMessage *message = NextMessageFrom(team, cookie)) {
if (message->what == MSG_REFS_RECEIVED) {
int32 index = --cookie;
result = CheckRefsMessage(team, cookie);
delete AppInfoFor(team)->RemoveMessage(index);
break;
status_t error = B_ERROR;
fLock.Lock();
error = B_OK;
if (fromNow || !FindMessage(messageCode)) {
// add sleeper
Sleeper *sleeper = new Sleeper;
error = sleeper->Init(messageCode);
if (error == B_OK) {
AddSleeper(sleeper);
fLock.Unlock();
// 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
@@ -541,6 +632,42 @@ LaunchContext::TerminatorEntry(void *data)
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
+49 -20
View File
@@ -18,23 +18,40 @@ enum {
// LaunchCaller
class LaunchCaller {
public:
LaunchCaller() : fNext(NULL) {}
virtual ~LaunchCaller() { if (fNext) delete fNext;}
virtual status_t operator()(const char *type, BList *messages, int32 argc,
const char **argv, team_id *team) = 0;
virtual int32 SupportsMessages() const { return 1; }
virtual bool SupportsArgv() const { return SupportsMessages() == 0; }
virtual bool SupportsRefs() const { return false; }
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
class LaunchContext {
public:
LaunchContext(LaunchCaller &caller);
LaunchContext();
~LaunchContext();
status_t operator()(const char *type, team_id *team);
status_t operator()(const char *type, BList *messages, int32 argc,
const char **argv, team_id *team);
status_t operator()(LaunchCaller &caller, const char *type, team_id *team);
status_t operator()(LaunchCaller &caller, const char *type,
BList *messages, int32 argc, const char **argv,
team_id *team);
void HandleMessage(BMessage *message);
@@ -44,24 +61,30 @@ public:
BMessage *NextMessageFrom(team_id team, int32 &cookie,
bigtime_t *time = NULL);
bool CheckNextMessage(team_id team, int32 &cookie, uint32 what);
bool CheckArgvMessage(team_id team, int32 &cookie,
bool CheckNextMessage(LaunchCaller &caller, team_id team, int32 &cookie,
uint32 what);
bool CheckArgvMessage(LaunchCaller &caller, team_id team, int32 &cookie,
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);
bool CheckArgvMessage(team_id team, int32 &cookie, const entry_ref *appRef,
const entry_ref *ref, int32 argc, const char **argv);
bool RemoveStandardArgvMessage(team_id team, const entry_ref *appRef);
bool RemoveArgvMessage(team_id team, const entry_ref *appRef, int32 argc,
const char **argv);
bool CheckMessageMessages(team_id team, int32 &cookie);
bool CheckMessageMessage(team_id team, int32 &cookie, int32 index);
bool CheckMessageMessage(team_id team, int32 &cookie,
bool CheckArgvMessage(LaunchCaller &caller, team_id team, int32 &cookie,
const entry_ref *appRef, const entry_ref *ref,
int32 argc, const char **argv);
bool CheckMessageMessages(LaunchCaller &caller, team_id team,
int32 &cookie);
bool CheckMessageMessage(LaunchCaller &caller, team_id team, int32 &cookie,
int32 index);
bool CheckMessageMessage(LaunchCaller &caller, team_id team, int32 &cookie,
const BMessage *message);
bool CheckRefsMessage(team_id team, int32 &cookie);
bool CheckRefsMessage(team_id team, int32 &cookie, const entry_ref *refs,
int32 count = 1);
bool RemoveRefsMessage(team_id team);
bool CheckRefsMessage(LaunchCaller &caller, team_id team, int32 &cookie);
bool CheckRefsMessage(LaunchCaller &caller, team_id team, int32 &cookie,
const entry_ref *refs, int32 count = 1);
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();
@@ -71,6 +94,7 @@ public:
private:
class Message;
class Sleeper;
class AppInfo;
private:
@@ -80,14 +104,19 @@ private:
AppInfo *CreateAppInfo(BMessenger messenger);
void TerminateApp(AppInfo *info);
Message *FindMessage(uint32 messageCode);
void AddSleeper(Sleeper *sleeper);
void RemoveSleeper(Sleeper *sleeper);
void NotifySleepers(uint32 messageCode);
int32 Terminator();
static int32 AppThreadEntry(void *data);
static int32 TerminatorEntry(void *data);
private:
LaunchCaller &fCaller;
BList fAppInfos;
BList fSleepers;
mutable BLocker fLock;
thread_id fAppThread;
thread_id fTerminator;