With the recent changes to the communication mechanism, fake_app_server

did not work anymore, and thus, the safemode with the current Bootscript
did not work.
It now does again.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@13192 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2005-06-16 21:33:29 +00:00
parent dec3c805d9
commit 91515d2132
4 changed files with 727 additions and 1103 deletions
+356 -143
View File
@@ -24,34 +24,32 @@
// Description: main manager object for the app_server
//
//------------------------------------------------------------------------------
#include <AppDefs.h>
#include <Accelerant.h>
#include <Entry.h>
#include <Path.h>
#include <AppDefs.h>
#include <Directory.h>
#include <PortLink.h>
#include <Entry.h>
#include <File.h>
#include <Message.h>
#include "AppServer.h"
#include "ServerProtocol.h"
#include "ServerApp.h"
#include <TokenSpace.h>
#if 0
#include <Path.h>
#include <PortLink.h>
#include <StopWatch.h>
#include "BitmapManager.h"
#include "ColorSet.h"
#include "DisplayDriver.h"
#include "ServerCursor.h"
#include "ServerWindow.h"
#include "DefaultDecorator.h"
#include "RGBColor.h"
#include "BitmapManager.h"
#include "CursorManager.h"
#include "Utils.h"
#include "FontServer.h"
#include "Desktop.h"
#include "RootLayer.h"
#endif
#include <StopWatch.h>
#include "RegistrarDefs.h"
#include "RGBColor.h"
#include "ServerApp.h"
#include "ServerCursor.h"
#include "ServerProtocol.h"
#include "SystemPalette.h"
#include "Utils.h"
#include "AppServer.h"
//#define DEBUG_KEYHANDLING
//#define DEBUG_SERVER
#ifdef DEBUG_KEYHANDLING
# include <stdio.h>
@@ -60,63 +58,133 @@
# define KBTRACE(x) ;
#endif
//#define DEBUG_SERVER
#ifdef DEBUG_SERVER
# define DEBUG 1
# include <Debug.h>
# define STRACE(x) _sPrintf x
# include <stdio.h>
# define STRACE(x) printf x
#else
# define STRACE(x) ;
#endif
// Globals
port_id gAppServerPort;
//! Used to access the app_server from new_decorator
static AppServer *sAppServer = NULL;
//! Default background color for workspaces
//RGBColor workspace_default_color(51,102,160);
/*!
\brief Constructor
This loads the default fonts, allocates all the major global variables, spawns the main housekeeping
threads, loads user preferences for the UI and decorator, and allocates various locks.
*/
AppServer::AppServer(void)
:
fCursorSem(-1),
fCursorArea(-1)
{
fMessagePort = create_port(200, SERVER_PORT_NAME);
if (fMessagePort == B_NO_MORE_PORTS)
debugger("app_server could not create message port");
fAppList = new BList(0);
fQuittingServer= false;
gAppServerPort = fMessagePort;
// Create the input port. The input_server will send it's messages here.
// TODO: If we want multiple user support we would need an individual
// port for each user and do the following for each RootLayer.
fServerInputPort = create_port(200, SERVER_INPUT_PORT);
if (fServerInputPort == B_NO_MORE_PORTS)
debugger("app_server could not create input port");
fAppList = new BList();
fQuittingServer = false;
make_decorator = NULL;
// We need this in order for new_decorator to be able to instantiate new decorators
sAppServer = this;
// This is necessary to mediate access between the Poller and app_server threads
fActiveAppLock= create_sem(1,"app_server_active_sem");
fActiveAppLock = create_sem(1,"app_server_active_sem");
// This locker is for app_server and Picasso to vy for control of the ServerApp list
fAppListLock= create_sem(1,"app_server_applist_sem");
fAppListLock = create_sem(1,"app_server_applist_sem");
// This locker is to mediate access to the make_decorator pointer
fDecoratorLock = create_sem(1,"app_server_decor_sem");
// Spawn our thread-monitoring thread
fPicassoThreadID= spawn_thread(PicassoThread,"picasso", B_NORMAL_PRIORITY, this);
fPicassoThreadID = spawn_thread(PicassoThread, "picasso", B_NORMAL_PRIORITY, this);
if (fPicassoThreadID >= 0)
resume_thread(fPicassoThreadID);
fDecoratorName ="Default";
#if 0
LaunchCursorThread();
#endif
}
/*!
\brief Destructor
Reached only when the server is asked to shut down in Test mode. Kills all apps, shuts down the
desktop, kills the housekeeping threads, etc.
*/
AppServer::~AppServer(void)
{
debugger("We shouldn't be here! MainLoop()::B_QUIT_REQUESTED should see if we can exit the server.\n");
/*
ServerApp *tempapp;
int32 i;
acquire_sem(fAppListLock);
for(i=0;i<fAppList->CountItems();i++)
{
tempapp=(ServerApp *)fAppList->ItemAt(i);
if(tempapp!=NULL)
delete tempapp;
}
delete fAppList;
release_sem(fAppListLock);
delete bitmapmanager;
delete gDesktop;
// If these threads are still running, kill them - after this, if exit_poller
// is deleted, who knows what will happen... These things will just return an
// error and fail if the threads have already exited.
kill_thread(fPicassoThreadID);
kill_thread(fCursorThreadID);
kill_thread(fISThreadID);
delete fontserver;
make_decorator=NULL;
*/
}
/*!
\brief Thread function for watching for dead apps
\param data Pointer to the app_server to which the thread belongs
\return Throwaway value - always 0
*/
int32
AppServer::PicassoThread(void *data)
{
int32 i;
AppServer *appserver=(AppServer*)data;
ServerApp *app;
for(;;)
{
i = 0;
#if 1
acquire_sem(appserver->fAppListLock);
for(;;)
{
app=(ServerApp*)appserver->fAppList->ItemAt(i++);
if(!app)
for (;;) {
acquire_sem(sAppServer->fAppListLock);
for (int32 i = 0;;) {
ServerApp *app = (ServerApp *)sAppServer->fAppList->ItemAt(i++);
if (!app)
break;
app->PingTarget();
}
release_sem(appserver->fAppListLock);
#endif
release_sem(sAppServer->fAppListLock);
// we do this every other second so as not to suck *too* many CPU cycles
snooze(1000000);
}
@@ -124,6 +192,28 @@ AppServer::PicassoThread(void *data)
}
/*!
\brief Starts Input Server
*/
void
AppServer::LaunchInputServer()
{
}
/*!
\brief Starts the Cursor Thread
*/
void
AppServer::LaunchCursorThread()
{
}
/*!
\brief The call that starts it all...
\return Always 0
*/
thread_id
AppServer::Run(void)
{
@@ -137,23 +227,19 @@ AppServer::Run(void)
void
AppServer::MainLoop(void)
{
BPrivate::PortLink pmsg(-1,fMessagePort);
int32 code=0;
status_t err=B_OK;
while(1)
{
STRACE(("info: AppServer::MainLoop listening on port %ld.\n", fMessagePort));
err=pmsg.GetNextMessage(code);
BPrivate::PortLink pmsg(-1, fMessagePort);
if(err<B_OK)
{
STRACE(("MainLoop:pmsg.GetNextMessage failed\n"));
while (1) {
STRACE(("info: AppServer::MainLoop listening on port %ld.\n", fMessagePort));
int32 code;
status_t err = pmsg.GetNextMessage(code);
if (err < B_OK) {
STRACE(("MainLoop:pmsg.GetNextMessage() failed\n"));
continue;
}
switch(code)
{
switch (code) {
case B_QUIT_REQUESTED:
case AS_CREATE_APP:
case AS_DELETE_APP:
@@ -164,25 +250,114 @@ AppServer::MainLoop(void)
case AS_SET_DECORATOR:
case AS_GET_DECORATOR:
case AS_R5_SET_DECORATOR:
DispatchMessage(code,pmsg);
DispatchMessage(code, pmsg);
break;
default:
{
STRACE(("Server::MainLoop received unexpected code %ld(offset %ld)\n",
code,code-SERVER_TRUE));
STRACE(("Server::MainLoop received unexpected code %ld (offset %ld)\n",
code, code - SERVER_TRUE));
break;
}
}
}
}
/*!
\brief Loads the specified decorator and sets the system's decorator to it.
\param path Path to the decorator to load
\return True if successful, false if not.
If the server cannot load the specified decorator, nothing changes. Passing a
NULL string to this function sets the decorator to the internal one.
*/
bool
AppServer::LoadDecorator(const char *path)
{
// Loads a window decorator based on the supplied path and forces a decorator update.
// If it cannot load the specified decorator, it will retain the current one and
// return false. Note that passing a NULL string to this function sets the decorator
// to the internal one.
// passing the string "Default" will set the window decorator to the app_server's
// internal one
if(!path)
{
make_decorator= NULL;
return true;
}
create_decorator *pcreatefunc= NULL;
status_t stat;
image_id addon;
addon = load_add_on(path);
if (addon < B_OK)
return false;
// As of now, we do nothing with decorator versions, but the possibility exists
// that the API will change even though I cannot forsee any reason to do so. If
// we *did* do anything with decorator versions, the assignment to a global would
// go here.
// Get the instantiation function
stat = get_image_symbol(addon, "instantiate_decorator",
B_SYMBOL_TYPE_TEXT, (void**)&pcreatefunc);
if (stat != B_OK) {
unload_add_on(addon);
return false;
}
BPath temppath(path);
fDecoratorName=temppath.Leaf();
acquire_sem(fDecoratorLock);
make_decorator=pcreatefunc;
fDecoratorID=addon;
release_sem(fDecoratorLock);
return true;
}
//! Loads decorator settings on disk or the default if settings are invalid
void
AppServer::InitDecorators(void)
{
BMessage settings;
BDirectory dir;
if (dir.SetTo(SERVER_SETTINGS_DIR) == B_ENTRY_NOT_FOUND)
create_directory(SERVER_SETTINGS_DIR, 0777);
BString path(SERVER_SETTINGS_DIR);
path += "DecoratorSettings";
BFile file(path.String(), B_READ_ONLY);
if (file.InitCheck() == B_OK
&& settings.Unflatten(&file) == B_OK) {
BString itemtext;
if (settings.FindString("decorator", &itemtext) == B_OK) {
path.SetTo(DECORATORS_DIR);
path += itemtext;
if (LoadDecorator(path.String()))
return;
}
}
// We got this far, so something must have gone wrong. We set make_decorator
// to NULL so that the decorator allocation routine knows to utilize the included
// default decorator instead of an addon.
make_decorator = NULL;
}
/*!
\brief Message handling function for all messages sent to the app_server
\param code ID of the message sent
\param buffer Attachment buffer for the message.
*/
void
AppServer::DispatchMessage(int32 code, BPrivate::PortLink &msg)
{
switch(code)
{
#if 1
switch (code) {
case AS_CREATE_APP:
{
// Create the ServerApp to node monitor a new BApplication
@@ -195,81 +370,78 @@ AppServer::DispatchMessage(int32 code, BPrivate::PortLink &msg)
// 4) char * - signature of the regular app
// Find the necessary data
team_id clientTeamID=-1;
port_id clientLooperPort=-1;
port_id app_port=-1;
int32 htoken=B_NULL_TOKEN;
char *app_signature=NULL;
team_id clientTeamID = -1;
port_id clientLooperPort = -1;
port_id clientReplyPort = -1;
int32 htoken = B_NULL_TOKEN;
char *appSignature = NULL;
msg.Read<port_id>(&app_port);
msg.Read<port_id>(&clientReplyPort);
msg.Read<port_id>(&clientLooperPort);
msg.Read<team_id>(&clientTeamID);
msg.Read<int32>(&htoken);
msg.ReadString(&app_signature);
// Create the ServerApp subthread for this app
acquire_sem(fAppListLock);
port_id server_listen=create_port(DEFAULT_MONITOR_PORT_SIZE, app_signature);
if(server_listen<B_OK)
{
release_sem(fAppListLock);
if (msg.ReadString(&appSignature) != B_OK)
break;
port_id serverListen = create_port(DEFAULT_MONITOR_PORT_SIZE, appSignature);
if (serverListen < B_OK) {
printf("No more ports left. Time to crash. Have a nice day! :)\n");
break;
}
ServerApp *newapp=NULL;
newapp= new ServerApp(app_port,server_listen, clientLooperPort, clientTeamID,
htoken, app_signature);
// we let the application own the port, so that we get aware when it's gone
if (set_port_owner(serverListen, clientTeamID) < B_OK) {
delete_port(serverListen);
printf("Could not transfer port ownership to client %ld!\n", clientTeamID);
break;
}
// Create the ServerApp subthread for this app
acquire_sem(fAppListLock);
ServerApp *app = new ServerApp(clientReplyPort, serverListen, clientLooperPort,
clientTeamID, htoken, appSignature);
// add the new ServerApp to the known list of ServerApps
fAppList->AddItem(newapp);
fAppList->AddItem(app);
release_sem(fAppListLock);
BPrivate::PortLink replylink(app_port);
BPrivate::PortLink replylink(clientReplyPort);
replylink.StartMessage(SERVER_TRUE);
replylink.Attach<int32>(newapp->fMessagePort);
replylink.Attach<int32>(serverListen);
replylink.Flush();
// This is necessary because BPrivate::PortLink::ReadString allocates memory
if(app_signature)
free(app_signature);
// This is necessary because BPortLink::ReadString allocates memory
free(appSignature);
break;
}
case AS_DELETE_APP:
{
// Delete a ServerApp. Received only from the respective ServerApp when a
// BApplication asks it to quit.
// Attached Data:
// 1) thread_id - thread ID of the ServerApp to be deleted
int32 i=0,
appnum=fAppList->CountItems();
ServerApp *srvapp=NULL;
thread_id srvapp_id=-1;
if(msg.Read<thread_id>(&srvapp_id)<B_OK)
int32 i = 0, appnum = fAppList->CountItems();
ServerApp *srvapp = NULL;
thread_id srvapp_id = -1;
if (msg.Read<thread_id>(&srvapp_id) < B_OK)
break;
acquire_sem(fAppListLock);
// Run through the list of apps and nuke the proper one
for(i= 0; i < appnum; i++)
{
srvapp=(ServerApp *)fAppList->ItemAt(i);
for (i = 0; i < appnum; i++) {
srvapp = (ServerApp *)fAppList->ItemAt(i);
if(srvapp != NULL && srvapp->fMonitorThreadID== srvapp_id)
{
srvapp=(ServerApp *)fAppList->RemoveItem(i);
if(srvapp)
{
status_t temp;
wait_for_thread(srvapp_id, &temp);
if (srvapp != NULL && srvapp->MonitorThreadID() == srvapp_id) {
srvapp = (ServerApp *)fAppList->RemoveItem(i);
if (srvapp) {
delete srvapp;
srvapp= NULL;
srvapp = NULL;
}
break; // jump out of our for() loop
}
@@ -278,53 +450,94 @@ AppServer::DispatchMessage(int32 code, BPrivate::PortLink &msg)
release_sem(fAppListLock);
break;
}
#endif
case AS_QUERY_FONTS_CHANGED:
case B_QUIT_REQUESTED:
{
// Seeing how the client merely wants an answer, we'll skip the BPrivate::PortLink
// and all its overhead and just write the code to port.
port_id replyport;
if (msg.Read<port_id>(&replyport) < B_OK)
break;
BPrivate::PortLink replylink(replyport);
replylink.StartMessage(SERVER_FALSE);
replylink.Flush();
break;
}
case AS_GET_DECORATOR:
{
// Attached Data:
// 1) port_id reply port
port_id replyport=-1;
if(msg.Read<port_id>(&replyport)<B_OK)
return;
BPrivate::PortLink replylink(replyport);
replylink.StartMessage(AS_GET_DECORATOR);
replylink.AttachString("none");
replylink.Flush();
break;
}
case AS_UPDATED_CLIENT_FONTLIST:
case AS_SET_UI_COLORS:
case AS_SET_DECORATOR:
case AS_R5_SET_DECORATOR:
case AS_SET_SYSCURSOR_DEFAULTS:
{
break;
}
default:
// we should never get here.
break;
}
}
/*!
\brief Send a quick (no attachments) message to all applications
Quite useful for notification for things like server shutdown, system
color changes, etc.
*/
void
AppServer::Broadcast(int32 code)
{
acquire_sem(fAppListLock);
for (int32 i = 0; i < fAppList->CountItems(); i++) {
ServerApp *app = (ServerApp *)fAppList->ItemAt(i);
if (!app)
{ printf("PANIC in AppServer::Broadcast()\n"); continue; }
app->PostMessage(code);
}
release_sem(fAppListLock);
}
/*!
\brief Finds the application with the given signature
\param sig MIME signature of the application to find
\return the corresponding ServerApp or NULL if not found
This call should be made only when necessary because it locks the app list
while it does its searching.
*/
ServerApp *
AppServer::FindApp(const char *sig)
{
if (!sig)
return NULL;
ServerApp *foundapp=NULL;
acquire_sem(fAppListLock);
for(int32 i=0; i<fAppList->CountItems();i++)
{
foundapp=(ServerApp*)fAppList->ItemAt(i);
if(foundapp && foundapp->Title() == sig)
{
release_sem(fAppListLock);
return foundapp;
}
}
release_sem(fAppListLock);
// couldn't find a match
return NULL;
}
// #pragma mark -
/*!
\brief Entry function to run the entire server
\param argc Number of command-line arguments present
\param argv String array of the command-line arguments
\return -1 if the app_server is already running, 0 if everything's OK.
*/
int
main(int argc, char **argv)
main(int argc, char** argv)
{
// There can be only one....
if (find_port(SERVER_PORT_NAME) != B_NAME_NOT_FOUND)
if (find_port(SERVER_PORT_NAME) >= B_OK)
return -1;
srand(real_time_clock_usecs());
AppServer app_server;
app_server.Run();
return 0;
+61 -6
View File
@@ -1,5 +1,11 @@
#ifndef _OPENBEOS_APP_SERVER_H_
#define _OPENBEOS_APP_SERVER_H_
/*
* Copyright (c) 2001-2005, Haiku, Inc.
* Distributed under the terms of the MIT license.
*
* Author: DarkWyrm <[email protected]>
*/
#ifndef _HAIKU_APP_SERVER_H_
#define _HAIKU_APP_SERVER_H_
#include <OS.h>
#include <Locker.h>
@@ -21,6 +27,15 @@ namespace BPrivate {
class PortLink;
};
/*!
\class AppServer AppServer.h
\brief main manager object for the app_server
File for the main app_server thread. This particular thread monitors for
application start and quit messages. It also starts the housekeeping threads
and initializes most of the server's globals.
*/
class AppServer {
public:
AppServer(void);
@@ -31,18 +46,58 @@ public:
thread_id Run(void);
void MainLoop(void);
bool LoadDecorator(const char *path);
void InitDecorators(void);
void DispatchMessage(int32 code, BPrivate::PortLink &link);
void Broadcast(int32 code);
ServerApp* FindApp(const char *sig);
private:
void LaunchCursorThread();
void LaunchInputServer();
friend Decorator* new_decorator(BRect rect, const char *title,
int32 wlook, int32 wfeel, int32 wflags, DisplayDriver *ddriver);
// global function pointer
create_decorator *make_decorator;
port_id fMessagePort;
bool fQuittingServer;
port_id fServerInputPort;
image_id fDecoratorID;
BString fDecoratorName;
volatile bool fQuittingServer;
BList *fAppList;
thread_id fPicassoThreadID;
thread_id fISThreadID;
thread_id fCursorThreadID;
sem_id fCursorSem;
area_id fCursorArea;
uint32 *fCursorAddr;
port_id fISASPort;
port_id fISPort;
sem_id fActiveAppLock, fAppListLock;
sem_id fActiveAppLock,
fAppListLock,
fDecoratorLock;
DisplayDriver *fDriver;
};
extern AppServer *app_server;
Decorator *new_decorator(BRect rect, const char *title, int32 wlook, int32 wfeel,
int32 wflags, DisplayDriver *ddriver);
#endif
extern BitmapManager *bitmapmanager;
extern ColorSet gui_colorset;
extern AppServer *app_server;
extern port_id gAppServerPort;
#endif /* _HAIKU_APP_SERVER_H_ */
File diff suppressed because it is too large Load Diff
+61 -36
View File
@@ -30,17 +30,15 @@
#include <OS.h>
#include <String.h>
#include <LinkMsgReader.h>
#include <LinkMsgSender.h>
//#include "FMWList.h"
#include <PortLink.h>
class AppServer;
class AreaPool;
class BMessage;
class BList;
class DisplayDriver;
class ServerPicture;
class ServerCursor;
class ServerBitmap;
class AreaPool;
namespace BPrivate {
class PortLink;
@@ -50,64 +48,91 @@ namespace BPrivate {
\class ServerApp ServerApp.h
\brief Counterpart to BApplication within the app_server
*/
class ServerApp
{
class ServerApp {
public:
ServerApp(port_id sendport, port_id rcvport, port_id clientLooperPort,
team_id clientTeamID, int32 handlerID, char *signature);
virtual ~ServerApp(void);
team_id clientTeamID, int32 handlerID, const char* signature);
virtual ~ServerApp(void);
bool Run(void);
static int32 MonitorApp(void *data);
/*
TODO: These aren't even implemented...
void Lock(void);
void Unlock(void);
bool IsLocked(void);
*/
/*!
\brief Determines whether the application is the active one
\return true if active, false if not.
*/
bool IsActive(void) const { return fIsActive; }
void Activate(bool value);
bool PingTarget(void);
void PostMessage(int32 code);
void SendMessageToClient( const BMessage* msg ) const;
void SetAppCursor(void);
team_id ClientTeamID();
team_id ClientTeamID() const;
thread_id MonitorThreadID() const;
const char * Title() const { return fSignature.String(); }
protected:
friend class AppServer;
friend class ServerWindow;
const char *Title() const { return fSignature.String(); }
void DispatchMessage(int32 code, BPrivate::LinkReceiver &link);
int32 CountBitmaps() const;
ServerBitmap *FindBitmap(int32 token) const;
port_id fClientAppPort,
fMessagePort,
// TODO: find out why there is both the app port and the looper port. Do
// we really need both?
fClientLooperPort;
BString fSignature;
thread_id fMonitorThreadID;
team_id fClientTeamID;
BPrivate::LinkReceiver *fMsgReader;
BPrivate::LinkSender *fMsgSender;
int32 CountPictures() const;
ServerPicture *FindPicture(int32 token) const;
/* BList *fSWindowList,
AreaPool *AppAreaPool() { return fSharedMem; }
private:
void DispatchMessage(int32 code, BPrivate::LinkReceiver &link);
static int32 MonitorApp(void *data);
// our BApplication's event port
port_id fClientAppPort;
// port we receive messages from our BApplication
port_id fMessagePort;
// TODO: find out why there is both the app port and the looper port. Do
// we really need both? Actually, we aren't using any of these ports,
// as BAppServerLink/BPortlink's messages always contain the reply port
// To send a message to the client, write a BMessage to this port
port_id fClientLooperPort;
BString fSignature;
thread_id fMonitorThreadID;
team_id fClientTeamID;
BPrivate::PortLink fLink;
// TODO:
// - Are really Bitmaps and Pictures stored per application and not globally ?
// - As we reference these stuff by token, what about putting them in hash tables ?
BList *fSWindowList,
*fBitmapList,
*fPictureList;
*/ sem_id fLockSem;
ServerCursor *fAppCursor;
// TODO: Not used.
sem_id fLockSem;
bool fCursorHidden;
bool fIsActive;
int32 fHandlerToken;
// token ID of the BApplication's BHandler object.
// Used for BMessage target specification
// TODO: Is it still needed ? We aren't using it.
//int32 fHandlerToken;
AreaPool *fSharedMem;
bool fQuitting;
};
#endif
#endif // _SERVERAPP_H_