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