xref: /haiku/src/servers/app/AppServer.cpp (revision b671e9bbdbd10268a042b4f4cc4317ccd03d105e)
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