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