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 gInputManager = new InputManager(); 132 133 // Create the font server and scan the proper directories. 134 gFontManager = new FontManager; 135 if (gFontManager->InitCheck() != B_OK) 136 debugger("font manager could not be initialized!"); 137 138 gFontManager->Run(); 139 140 gScreenManager = new ScreenManager(); 141 gScreenManager->Run(); 142 143 // Create the bitmap allocator. Object declared in BitmapManager.cpp 144 gBitmapManager = new BitmapManager(); 145 146 // Initialize SIMD flags 147 detect_simd(); 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) 180 { 181 BAutolock locker(fDesktopLock); 182 Desktop* desktop = NULL; 183 try { 184 desktop = new Desktop(userID); 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) 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 return desktop; 221 } 222 223 return NULL; 224 } 225 226 227 /*! \brief Message handling function for all messages sent to the app_server 228 \param code ID of the message sent 229 \param buffer Attachment buffer for the message. 230 231 */ 232 void 233 AppServer::_DispatchMessage(int32 code, BPrivate::LinkReceiver& msg) 234 { 235 switch (code) { 236 case AS_GET_DESKTOP: 237 { 238 port_id replyPort; 239 if (msg.Read<port_id>(&replyPort) < B_OK) 240 break; 241 242 int32 userID; 243 msg.Read<int32>(&userID); 244 245 Desktop* desktop = _FindDesktop(userID); 246 if (desktop == NULL) { 247 // we need to create a new desktop object for this user 248 // TODO: test if the user exists on the system 249 // TODO: maybe have a separate AS_START_DESKTOP_SESSION for 250 // authorizing the user 251 desktop = _CreateDesktop(userID); 252 } 253 254 BPrivate::LinkSender reply(replyPort); 255 if (desktop != NULL) { 256 reply.StartMessage(B_OK); 257 reply.Attach<port_id>(desktop->MessagePort()); 258 } else 259 reply.StartMessage(B_ERROR); 260 261 reply.Flush(); 262 break; 263 } 264 265 #if TEST_MODE 266 case B_QUIT_REQUESTED: 267 { 268 // We've been asked to quit, so (for now) broadcast to all 269 // desktops to quit. This situation will occur only when the server 270 // is compiled as a regular Be application. 271 272 fQuitting = true; 273 274 while (fDesktops.CountItems() > 0) { 275 Desktop *desktop = fDesktops.RemoveItemAt(0); 276 277 thread_id thread = desktop->Thread(); 278 desktop->PostMessage(B_QUIT_REQUESTED); 279 280 // we just wait for the desktop to kill itself 281 status_t status; 282 wait_for_thread(thread, &status); 283 } 284 285 delete this; 286 287 // we are now clear to exit 288 exit(0); 289 break; 290 } 291 #endif 292 293 default: 294 STRACE(("Server::MainLoop received unexpected code %ld (offset %ld)\n", 295 code, code - SERVER_TRUE)); 296 break; 297 } 298 } 299 300 301 // #pragma mark - 302 303 304 int 305 main(int argc, char** argv) 306 { 307 // There can be only one.... 308 if (find_port(SERVER_PORT_NAME) >= B_OK) 309 return -1; 310 311 srand(real_time_clock_usecs()); 312 313 AppServer* server = new AppServer; 314 server->RunLooper(); 315 316 return 0; 317 } 318