1 /* 2 * Copyright 2001-2009, Haiku, Inc. 3 * Distributed under the terms of the MIT license. 4 * 5 * Authors: 6 * DarkWyrm <bpmagic@columbus.rr.com> 7 * Axel Dörfler, axeld@pinc-software.de 8 * Stephan Aßmus <superstippi@gmx.de> 9 * Christian Packmann 10 */ 11 12 13 #include "AppServer.h" 14 15 #include "BitmapManager.h" 16 #include "Desktop.h" 17 #include "FontManager.h" 18 #include "InputManager.h" 19 #include "ScreenManager.h" 20 #include "ServerProtocol.h" 21 22 #include <PortLink.h> 23 24 #include <syslog.h> 25 26 27 //#define DEBUG_SERVER 28 #ifdef DEBUG_SERVER 29 # include <stdio.h> 30 # define STRACE(x) printf x 31 #else 32 # define STRACE(x) ; 33 #endif 34 35 36 // Globals 37 port_id gAppServerPort; 38 static AppServer* sAppServer; 39 BTokenSpace gTokenSpace; 40 uint32 gAppServerSIMDFlags = 0; 41 42 43 /*! Detect SIMD flags for use in AppServer. Checks all CPUs in the system 44 and chooses the minimum supported set of instructions. 45 */ 46 static void 47 detect_simd() 48 { 49 #if __INTEL__ 50 // Only scan CPUs for which we are certain the SIMD flags are properly 51 // defined. 52 const char* vendorNames[] = { 53 "GenuineIntel", 54 "AuthenticAMD", 55 "CentaurHauls", // Via CPUs, MMX and SSE support 56 "RiseRiseRise", // should be MMX-only 57 "CyrixInstead", // MMX-only, but custom MMX extensions 58 "GenuineTMx86", // MMX and SSE 59 0 60 }; 61 62 system_info systemInfo; 63 if (get_system_info(&systemInfo) != B_OK) 64 return; 65 66 // We start out with all flags set and end up with only those flags 67 // supported across all CPUs found. 68 uint32 appServerSIMD = 0xffffffff; 69 70 for (int32 cpu = 0; cpu < systemInfo.cpu_count; cpu++) { 71 cpuid_info cpuInfo; 72 get_cpuid(&cpuInfo, 0, cpu); 73 74 // Get the vendor string and terminate it manually 75 char vendor[13]; 76 memcpy(vendor, cpuInfo.eax_0.vendor_id, 12); 77 vendor[12] = 0; 78 79 bool vendorFound = false; 80 for (uint32 i = 0; vendorNames[i] != 0; i++) { 81 if (strcmp(vendor, vendorNames[i]) == 0) 82 vendorFound = true; 83 } 84 85 uint32 cpuSIMD = 0; 86 uint32 maxStdFunc = cpuInfo.regs.eax; 87 if (vendorFound && maxStdFunc >= 1) { 88 get_cpuid(&cpuInfo, 1, 0); 89 uint32 edx = cpuInfo.regs.edx; 90 if (edx & (1 << 23)) 91 cpuSIMD |= APPSERVER_SIMD_MMX; 92 if (edx & (1 << 25)) 93 cpuSIMD |= APPSERVER_SIMD_SSE; 94 } else { 95 // no flags can be identified 96 cpuSIMD = 0; 97 } 98 appServerSIMD &= cpuSIMD; 99 } 100 gAppServerSIMDFlags = appServerSIMD; 101 #endif // __INTEL__ 102 } 103 104 105 // #pragma mark - 106 107 108 /*! 109 \brief Constructor 110 111 This loads the default fonts, allocates all the major global variables, spawns the main housekeeping 112 threads, loads user preferences for the UI and decorator, and allocates various locks. 113 */ 114 AppServer::AppServer() 115 : 116 MessageLooper("app_server"), 117 fMessagePort(-1), 118 fDesktops(), 119 fDesktopLock("AppServerDesktopLock") 120 { 121 openlog("app_server", 0, LOG_DAEMON); 122 123 fMessagePort = create_port(DEFAULT_MONITOR_PORT_SIZE, SERVER_PORT_NAME); 124 if (fMessagePort < B_OK) 125 debugger("app_server could not create message port"); 126 127 fLink.SetReceiverPort(fMessagePort); 128 129 sAppServer = this; 130 131 // Initialize SIMD flags 132 detect_simd(); 133 134 gInputManager = new InputManager(); 135 136 // Create the font server and scan the proper directories. 137 gFontManager = new FontManager; 138 if (gFontManager->InitCheck() != B_OK) 139 debugger("font manager could not be initialized!"); 140 141 gFontManager->Run(); 142 143 gScreenManager = new ScreenManager(); 144 gScreenManager->Run(); 145 146 // Create the bitmap allocator. Object declared in BitmapManager.cpp 147 gBitmapManager = new BitmapManager(); 148 } 149 150 151 /*! \brief Destructor 152 Reached only when the server is asked to shut down in Test mode. 153 */ 154 AppServer::~AppServer() 155 { 156 delete gBitmapManager; 157 158 gScreenManager->Lock(); 159 gScreenManager->Quit(); 160 161 gFontManager->Lock(); 162 gFontManager->Quit(); 163 164 closelog(); 165 } 166 167 168 void 169 AppServer::RunLooper() 170 { 171 rename_thread(find_thread(NULL), "picasso"); 172 _message_thread((void*)this); 173 } 174 175 176 /*! \brief Creates a desktop object for an authorized user 177 */ 178 Desktop* 179 AppServer::_CreateDesktop(uid_t userID, const char* targetScreen) 180 { 181 BAutolock locker(fDesktopLock); 182 Desktop* desktop = NULL; 183 try { 184 desktop = new Desktop(userID, targetScreen); 185 186 status_t status = desktop->Init(); 187 if (status == B_OK) { 188 if (!desktop->Run()) 189 status = B_ERROR; 190 } 191 if (status == B_OK && !fDesktops.AddItem(desktop)) 192 status = B_NO_MEMORY; 193 194 if (status != B_OK) { 195 syslog(LOG_ERR, "Cannot initialize Desktop object: %s\n", 196 strerror(status)); 197 delete desktop; 198 return NULL; 199 } 200 } catch (...) { 201 // there is obviously no memory left 202 return NULL; 203 } 204 205 return desktop; 206 } 207 208 209 /*! \brief Finds the desktop object that belongs to a certain user 210 */ 211 Desktop* 212 AppServer::_FindDesktop(uid_t userID, const char* targetScreen) 213 { 214 BAutolock locker(fDesktopLock); 215 216 for (int32 i = 0; i < fDesktops.CountItems(); i++) { 217 Desktop* desktop = fDesktops.ItemAt(i); 218 219 if (desktop->UserID() == userID 220 && ((desktop->TargetScreen() == NULL && targetScreen == NULL) 221 || (desktop->TargetScreen() != NULL && targetScreen != NULL 222 && strcmp(desktop->TargetScreen(), targetScreen) == 0))) { 223 return desktop; 224 } 225 } 226 227 return NULL; 228 } 229 230 231 /*! \brief Message handling function for all messages sent to the app_server 232 \param code ID of the message sent 233 \param buffer Attachment buffer for the message. 234 235 */ 236 void 237 AppServer::_DispatchMessage(int32 code, BPrivate::LinkReceiver& msg) 238 { 239 switch (code) { 240 case AS_GET_DESKTOP: 241 { 242 Desktop* desktop = NULL; 243 244 port_id replyPort; 245 msg.Read<port_id>(&replyPort); 246 247 int32 userID; 248 msg.Read<int32>(&userID); 249 250 char* targetScreen = NULL; 251 msg.ReadString(&targetScreen); 252 if (targetScreen != NULL && strlen(targetScreen) == 0) { 253 free(targetScreen); 254 targetScreen = NULL; 255 } 256 257 int32 version; 258 if (msg.Read<int32>(&version) < B_OK 259 || version != AS_PROTOCOL_VERSION) { 260 syslog(LOG_ERR, "Application for user %ld with port %ld does " 261 "not support the current server protocol.\n", userID, 262 replyPort); 263 } else { 264 desktop = _FindDesktop(userID, targetScreen); 265 if (desktop == NULL) { 266 // we need to create a new desktop object for this user 267 // TODO: test if the user exists on the system 268 // TODO: maybe have a separate AS_START_DESKTOP_SESSION for 269 // authorizing the user 270 desktop = _CreateDesktop(userID, targetScreen); 271 } 272 } 273 274 free(targetScreen); 275 276 BPrivate::LinkSender reply(replyPort); 277 if (desktop != NULL) { 278 reply.StartMessage(B_OK); 279 reply.Attach<port_id>(desktop->MessagePort()); 280 } else 281 reply.StartMessage(B_ERROR); 282 283 reply.Flush(); 284 break; 285 } 286 287 #if TEST_MODE 288 case B_QUIT_REQUESTED: 289 { 290 // We've been asked to quit, so (for now) broadcast to all 291 // desktops to quit. This situation will occur only when the server 292 // is compiled as a regular Be application. 293 294 fQuitting = true; 295 296 while (fDesktops.CountItems() > 0) { 297 Desktop *desktop = fDesktops.RemoveItemAt(0); 298 299 thread_id thread = desktop->Thread(); 300 desktop->PostMessage(B_QUIT_REQUESTED); 301 302 // we just wait for the desktop to kill itself 303 status_t status; 304 wait_for_thread(thread, &status); 305 } 306 307 delete this; 308 309 // we are now clear to exit 310 exit(0); 311 break; 312 } 313 #endif 314 315 default: 316 STRACE(("Server::MainLoop received unexpected code %ld (offset %ld)\n", 317 code, code - SERVER_TRUE)); 318 break; 319 } 320 } 321 322 323 // #pragma mark - 324 325 326 int 327 main(int argc, char** argv) 328 { 329 // There can be only one.... 330 if (find_port(SERVER_PORT_NAME) >= B_OK) 331 return -1; 332 333 srand(real_time_clock_usecs()); 334 335 AppServer* server = new AppServer; 336 server->RunLooper(); 337 338 return 0; 339 } 340