xref: /haiku/src/system/kernel/messaging/MessagingService.cpp (revision 2d690920ac4d0cd27eb3c118fb2b0862615869e0)
1*2d690920SAxel Dörfler /*
2*2d690920SAxel Dörfler  * Copyright 2005, Ingo Weinhold, bonefish@users.sf.net. All rights reserved.
3*2d690920SAxel Dörfler  * Distributed under the terms of the MIT License.
4*2d690920SAxel Dörfler  */
5*2d690920SAxel Dörfler 
6*2d690920SAxel Dörfler // kernel-side implementation of the messaging service
7*2d690920SAxel Dörfler 
8*2d690920SAxel Dörfler #include <new>
9*2d690920SAxel Dörfler 
10*2d690920SAxel Dörfler #include <AutoDeleter.h>
11*2d690920SAxel Dörfler #include <KernelExport.h>
12*2d690920SAxel Dörfler #include <KMessage.h>
13*2d690920SAxel Dörfler #include <messaging.h>
14*2d690920SAxel Dörfler #include <MessagingServiceDefs.h>
15*2d690920SAxel Dörfler 
16*2d690920SAxel Dörfler #include "MessagingService.h"
17*2d690920SAxel Dörfler 
18*2d690920SAxel Dörfler //#define TRACE_MESSAGING_SERVICE
19*2d690920SAxel Dörfler #ifdef TRACE_MESSAGING_SERVICE
20*2d690920SAxel Dörfler #	define PRINT(x) dprintf x
21*2d690920SAxel Dörfler #else
22*2d690920SAxel Dörfler #	define PRINT(x) ;
23*2d690920SAxel Dörfler #endif
24*2d690920SAxel Dörfler 
25*2d690920SAxel Dörfler using namespace std;
26*2d690920SAxel Dörfler 
27*2d690920SAxel Dörfler static MessagingService *sMessagingService = NULL;
28*2d690920SAxel Dörfler 
29*2d690920SAxel Dörfler static const int32 kMessagingAreaSize = B_PAGE_SIZE * 4;
30*2d690920SAxel Dörfler 
31*2d690920SAxel Dörfler // init_messaging_service
32*2d690920SAxel Dörfler status_t
33*2d690920SAxel Dörfler init_messaging_service()
34*2d690920SAxel Dörfler {
35*2d690920SAxel Dörfler 	static char buffer[sizeof(MessagingService)];
36*2d690920SAxel Dörfler 
37*2d690920SAxel Dörfler 	if (!sMessagingService)
38*2d690920SAxel Dörfler 		sMessagingService = new(buffer) MessagingService;
39*2d690920SAxel Dörfler 
40*2d690920SAxel Dörfler 	status_t error = sMessagingService->InitCheck();
41*2d690920SAxel Dörfler 
42*2d690920SAxel Dörfler 	// cleanup on error
43*2d690920SAxel Dörfler 	if (error != B_OK) {
44*2d690920SAxel Dörfler 		dprintf("ERROR: Failed to init messaging service: %s\n",
45*2d690920SAxel Dörfler 			strerror(error));
46*2d690920SAxel Dörfler 		sMessagingService->~MessagingService();
47*2d690920SAxel Dörfler 		sMessagingService = NULL;
48*2d690920SAxel Dörfler 	}
49*2d690920SAxel Dörfler 
50*2d690920SAxel Dörfler 	return error;
51*2d690920SAxel Dörfler }
52*2d690920SAxel Dörfler 
53*2d690920SAxel Dörfler // _user_register_messaging_service
54*2d690920SAxel Dörfler /** \brief Called by the userland server to register itself as a messaging
55*2d690920SAxel Dörfler 		   service for the kernel.
56*2d690920SAxel Dörfler 	\param lockingSem A semaphore used for locking the shared data. Semaphore
57*2d690920SAxel Dörfler 		   counter must be initialized to 0.
58*2d690920SAxel Dörfler 	\param counterSem A semaphore released every time the kernel pushes a
59*2d690920SAxel Dörfler 		   command into an empty area. Semaphore counter must be initialized
60*2d690920SAxel Dörfler 		   to 0.
61*2d690920SAxel Dörfler 	\return
62*2d690920SAxel Dörfler 	- The ID of the kernel area used for communication, if everything went fine,
63*2d690920SAxel Dörfler 	- an error code otherwise.
64*2d690920SAxel Dörfler */
65*2d690920SAxel Dörfler area_id
66*2d690920SAxel Dörfler _user_register_messaging_service(sem_id lockSem, sem_id counterSem)
67*2d690920SAxel Dörfler {
68*2d690920SAxel Dörfler 	// check, if init_messaging_service() has been called yet
69*2d690920SAxel Dörfler 	if (!sMessagingService)
70*2d690920SAxel Dörfler 		return B_NO_INIT;
71*2d690920SAxel Dörfler 
72*2d690920SAxel Dörfler 	if (!sMessagingService->Lock())
73*2d690920SAxel Dörfler 		return B_BAD_VALUE;
74*2d690920SAxel Dörfler 
75*2d690920SAxel Dörfler 	area_id areaID;
76*2d690920SAxel Dörfler 	status_t error = sMessagingService->RegisterService(lockSem, counterSem,
77*2d690920SAxel Dörfler 		areaID);
78*2d690920SAxel Dörfler 
79*2d690920SAxel Dörfler 	sMessagingService->Unlock();
80*2d690920SAxel Dörfler 
81*2d690920SAxel Dörfler 	return (error != B_OK ? error : areaID);
82*2d690920SAxel Dörfler }
83*2d690920SAxel Dörfler 
84*2d690920SAxel Dörfler // _user_unregister_messaging_service
85*2d690920SAxel Dörfler status_t
86*2d690920SAxel Dörfler _user_unregister_messaging_service()
87*2d690920SAxel Dörfler {
88*2d690920SAxel Dörfler 	// check, if init_messaging_service() has been called yet
89*2d690920SAxel Dörfler 	if (!sMessagingService)
90*2d690920SAxel Dörfler 		return B_NO_INIT;
91*2d690920SAxel Dörfler 
92*2d690920SAxel Dörfler 	if (!sMessagingService->Lock())
93*2d690920SAxel Dörfler 		return B_BAD_VALUE;
94*2d690920SAxel Dörfler 
95*2d690920SAxel Dörfler 	status_t error = sMessagingService->UnregisterService();
96*2d690920SAxel Dörfler 
97*2d690920SAxel Dörfler 	sMessagingService->Unlock();
98*2d690920SAxel Dörfler 
99*2d690920SAxel Dörfler 	return error;
100*2d690920SAxel Dörfler }
101*2d690920SAxel Dörfler 
102*2d690920SAxel Dörfler 
103*2d690920SAxel Dörfler // send_message
104*2d690920SAxel Dörfler status_t
105*2d690920SAxel Dörfler send_message(const void *message, int32 messageSize,
106*2d690920SAxel Dörfler 	const messaging_target *targets, int32 targetCount)
107*2d690920SAxel Dörfler {
108*2d690920SAxel Dörfler 	// check, if init_messaging_service() has been called yet
109*2d690920SAxel Dörfler 	if (!sMessagingService)
110*2d690920SAxel Dörfler 		return B_NO_INIT;
111*2d690920SAxel Dörfler 
112*2d690920SAxel Dörfler 	if (!sMessagingService->Lock())
113*2d690920SAxel Dörfler 		return B_BAD_VALUE;
114*2d690920SAxel Dörfler 
115*2d690920SAxel Dörfler 	status_t error = sMessagingService->SendMessage(message, messageSize,
116*2d690920SAxel Dörfler 		targets, targetCount);
117*2d690920SAxel Dörfler 
118*2d690920SAxel Dörfler 	sMessagingService->Unlock();
119*2d690920SAxel Dörfler 
120*2d690920SAxel Dörfler 	return error;
121*2d690920SAxel Dörfler }
122*2d690920SAxel Dörfler 
123*2d690920SAxel Dörfler // send_message
124*2d690920SAxel Dörfler status_t
125*2d690920SAxel Dörfler send_message(const KMessage *message, const messaging_target *targets,
126*2d690920SAxel Dörfler 	int32 targetCount)
127*2d690920SAxel Dörfler {
128*2d690920SAxel Dörfler 	if (!message)
129*2d690920SAxel Dörfler 		return B_BAD_VALUE;
130*2d690920SAxel Dörfler 
131*2d690920SAxel Dörfler 	return send_message(message->Buffer(), message->ContentSize(), targets,
132*2d690920SAxel Dörfler 		targetCount);
133*2d690920SAxel Dörfler }
134*2d690920SAxel Dörfler 
135*2d690920SAxel Dörfler 
136*2d690920SAxel Dörfler // #pragma mark -
137*2d690920SAxel Dörfler 
138*2d690920SAxel Dörfler // constructor
139*2d690920SAxel Dörfler MessagingArea::MessagingArea()
140*2d690920SAxel Dörfler {
141*2d690920SAxel Dörfler }
142*2d690920SAxel Dörfler 
143*2d690920SAxel Dörfler // destructor
144*2d690920SAxel Dörfler MessagingArea::~MessagingArea()
145*2d690920SAxel Dörfler {
146*2d690920SAxel Dörfler 	if (fID >= 0)
147*2d690920SAxel Dörfler 		delete_area(fID);
148*2d690920SAxel Dörfler }
149*2d690920SAxel Dörfler 
150*2d690920SAxel Dörfler // Create
151*2d690920SAxel Dörfler MessagingArea *
152*2d690920SAxel Dörfler MessagingArea::Create(sem_id lockSem, sem_id counterSem)
153*2d690920SAxel Dörfler {
154*2d690920SAxel Dörfler 	// allocate the object on the heap
155*2d690920SAxel Dörfler 	MessagingArea *area = new(nothrow) MessagingArea;
156*2d690920SAxel Dörfler 	if (!area)
157*2d690920SAxel Dörfler 		return NULL;
158*2d690920SAxel Dörfler 
159*2d690920SAxel Dörfler 	// create the area
160*2d690920SAxel Dörfler 	area->fID = create_area("messaging", (void**)&area->fHeader,
161*2d690920SAxel Dörfler 		B_ANY_KERNEL_ADDRESS, kMessagingAreaSize, B_FULL_LOCK,
162*2d690920SAxel Dörfler 		B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA | B_USER_CLONEABLE_AREA);
163*2d690920SAxel Dörfler 	if (area->fID < 0) {
164*2d690920SAxel Dörfler 		delete area;
165*2d690920SAxel Dörfler 		return NULL;
166*2d690920SAxel Dörfler 	}
167*2d690920SAxel Dörfler 
168*2d690920SAxel Dörfler 	// finish the initialization of the object
169*2d690920SAxel Dörfler 	area->fSize = kMessagingAreaSize;
170*2d690920SAxel Dörfler 	area->fLockSem = lockSem;
171*2d690920SAxel Dörfler 	area->fCounterSem = counterSem;
172*2d690920SAxel Dörfler 	area->fNextArea = NULL;
173*2d690920SAxel Dörfler 	area->InitHeader();
174*2d690920SAxel Dörfler 
175*2d690920SAxel Dörfler 	return area;
176*2d690920SAxel Dörfler }
177*2d690920SAxel Dörfler 
178*2d690920SAxel Dörfler // InitHeader
179*2d690920SAxel Dörfler void
180*2d690920SAxel Dörfler MessagingArea::InitHeader()
181*2d690920SAxel Dörfler {
182*2d690920SAxel Dörfler 	fHeader->lock_counter = 1;			// create locked
183*2d690920SAxel Dörfler 	fHeader->size = fSize;
184*2d690920SAxel Dörfler 	fHeader->kernel_area = fID;
185*2d690920SAxel Dörfler 	fHeader->next_kernel_area = (fNextArea ? fNextArea->ID() : -1);
186*2d690920SAxel Dörfler 	fHeader->command_count = 0;
187*2d690920SAxel Dörfler 	fHeader->first_command = 0;
188*2d690920SAxel Dörfler 	fHeader->last_command = 0;
189*2d690920SAxel Dörfler }
190*2d690920SAxel Dörfler 
191*2d690920SAxel Dörfler // CheckCommandSize
192*2d690920SAxel Dörfler bool
193*2d690920SAxel Dörfler MessagingArea::CheckCommandSize(int32 dataSize)
194*2d690920SAxel Dörfler {
195*2d690920SAxel Dörfler 	int32 size = sizeof(messaging_command) + dataSize;
196*2d690920SAxel Dörfler 
197*2d690920SAxel Dörfler 	return (dataSize >= 0
198*2d690920SAxel Dörfler 		&& size <= kMessagingAreaSize - (int32)sizeof(messaging_area_header));
199*2d690920SAxel Dörfler }
200*2d690920SAxel Dörfler 
201*2d690920SAxel Dörfler // Lock
202*2d690920SAxel Dörfler bool
203*2d690920SAxel Dörfler MessagingArea::Lock()
204*2d690920SAxel Dörfler {
205*2d690920SAxel Dörfler 	// benaphore-like locking
206*2d690920SAxel Dörfler 	if (atomic_add(&fHeader->lock_counter, 1) == 0)
207*2d690920SAxel Dörfler 		return true;
208*2d690920SAxel Dörfler 
209*2d690920SAxel Dörfler 	return (acquire_sem(fLockSem) == B_OK);
210*2d690920SAxel Dörfler }
211*2d690920SAxel Dörfler 
212*2d690920SAxel Dörfler // Unlock
213*2d690920SAxel Dörfler void
214*2d690920SAxel Dörfler MessagingArea::Unlock()
215*2d690920SAxel Dörfler {
216*2d690920SAxel Dörfler 	if (atomic_add(&fHeader->lock_counter, -1) > 1)
217*2d690920SAxel Dörfler 		release_sem(fLockSem);
218*2d690920SAxel Dörfler }
219*2d690920SAxel Dörfler 
220*2d690920SAxel Dörfler // ID
221*2d690920SAxel Dörfler area_id
222*2d690920SAxel Dörfler MessagingArea::ID() const
223*2d690920SAxel Dörfler {
224*2d690920SAxel Dörfler 	return fID;
225*2d690920SAxel Dörfler }
226*2d690920SAxel Dörfler 
227*2d690920SAxel Dörfler // Size
228*2d690920SAxel Dörfler int32
229*2d690920SAxel Dörfler MessagingArea::Size() const
230*2d690920SAxel Dörfler {
231*2d690920SAxel Dörfler 	return fSize;
232*2d690920SAxel Dörfler }
233*2d690920SAxel Dörfler 
234*2d690920SAxel Dörfler // AllocateCommand
235*2d690920SAxel Dörfler void *
236*2d690920SAxel Dörfler MessagingArea::AllocateCommand(uint32 commandWhat, int32 dataSize,
237*2d690920SAxel Dörfler 	bool &wasEmpty)
238*2d690920SAxel Dörfler {
239*2d690920SAxel Dörfler 	int32 size = sizeof(messaging_command) + dataSize;
240*2d690920SAxel Dörfler 
241*2d690920SAxel Dörfler 	if (dataSize < 0 || size > fSize - (int32)sizeof(messaging_area_header))
242*2d690920SAxel Dörfler 		return NULL;
243*2d690920SAxel Dörfler 
244*2d690920SAxel Dörfler 	// the area is used as a ring buffer
245*2d690920SAxel Dörfler 	int32 startOffset = sizeof(messaging_area_header);
246*2d690920SAxel Dörfler 
247*2d690920SAxel Dörfler 	// the simple case first: the area is empty
248*2d690920SAxel Dörfler 	int32 commandOffset;
249*2d690920SAxel Dörfler 	wasEmpty = (fHeader->command_count == 0);
250*2d690920SAxel Dörfler 	if (wasEmpty) {
251*2d690920SAxel Dörfler 		commandOffset = startOffset;
252*2d690920SAxel Dörfler 
253*2d690920SAxel Dörfler 		// update the header
254*2d690920SAxel Dörfler 		fHeader->command_count++;
255*2d690920SAxel Dörfler 		fHeader->first_command = fHeader->last_command = commandOffset;
256*2d690920SAxel Dörfler 	} else {
257*2d690920SAxel Dörfler 		int32 firstCommandOffset = fHeader->first_command;
258*2d690920SAxel Dörfler 		int32 lastCommandOffset = fHeader->last_command;
259*2d690920SAxel Dörfler 		int32 firstCommandSize;
260*2d690920SAxel Dörfler 		int32 lastCommandSize;
261*2d690920SAxel Dörfler 		messaging_command *firstCommand = _CheckCommand(firstCommandOffset,
262*2d690920SAxel Dörfler 			firstCommandSize);
263*2d690920SAxel Dörfler 		messaging_command *lastCommand = _CheckCommand(lastCommandOffset,
264*2d690920SAxel Dörfler 			lastCommandSize);
265*2d690920SAxel Dörfler 		if (!firstCommand || !lastCommand) {
266*2d690920SAxel Dörfler 			// something has been screwed up
267*2d690920SAxel Dörfler 			return NULL;
268*2d690920SAxel Dörfler 		}
269*2d690920SAxel Dörfler 
270*2d690920SAxel Dörfler 		// find space for the command
271*2d690920SAxel Dörfler 		if (firstCommandOffset < lastCommandOffset) {
272*2d690920SAxel Dörfler 			// not wrapped
273*2d690920SAxel Dörfler 			// try to allocate after the last command
274*2d690920SAxel Dörfler 			if (size <= fSize - (lastCommandOffset + lastCommandSize)) {
275*2d690920SAxel Dörfler 				commandOffset = (lastCommandOffset + lastCommandSize);
276*2d690920SAxel Dörfler 			} else {
277*2d690920SAxel Dörfler 				// is there enough space before the first command?
278*2d690920SAxel Dörfler 				if (size > firstCommandOffset - startOffset)
279*2d690920SAxel Dörfler 					return NULL;
280*2d690920SAxel Dörfler 				commandOffset = startOffset;
281*2d690920SAxel Dörfler 			}
282*2d690920SAxel Dörfler 		} else {
283*2d690920SAxel Dörfler 			// wrapped: we can only allocate between the last and the first
284*2d690920SAxel Dörfler 			// command
285*2d690920SAxel Dörfler 			commandOffset = lastCommandOffset + lastCommandSize;
286*2d690920SAxel Dörfler 			if (size > firstCommandOffset - commandOffset)
287*2d690920SAxel Dörfler 				return NULL;
288*2d690920SAxel Dörfler 		}
289*2d690920SAxel Dörfler 
290*2d690920SAxel Dörfler 		// update the header and the last command
291*2d690920SAxel Dörfler 		fHeader->command_count++;
292*2d690920SAxel Dörfler 		lastCommand->next_command = fHeader->last_command = commandOffset;
293*2d690920SAxel Dörfler 	}
294*2d690920SAxel Dörfler 
295*2d690920SAxel Dörfler 	// init the command
296*2d690920SAxel Dörfler 	messaging_command *command
297*2d690920SAxel Dörfler 		= (messaging_command*)((char*)fHeader + commandOffset);
298*2d690920SAxel Dörfler 	command->next_command = 0;
299*2d690920SAxel Dörfler 	command->command = commandWhat;
300*2d690920SAxel Dörfler 	command->size = size;
301*2d690920SAxel Dörfler 
302*2d690920SAxel Dörfler 	return command->data;
303*2d690920SAxel Dörfler }
304*2d690920SAxel Dörfler 
305*2d690920SAxel Dörfler // CommitCommand
306*2d690920SAxel Dörfler void
307*2d690920SAxel Dörfler MessagingArea::CommitCommand()
308*2d690920SAxel Dörfler {
309*2d690920SAxel Dörfler 	// TODO: If invoked while locked, we should supply B_DO_NOT_RESCHEDULE.
310*2d690920SAxel Dörfler 	release_sem(fCounterSem);
311*2d690920SAxel Dörfler }
312*2d690920SAxel Dörfler 
313*2d690920SAxel Dörfler // SetNextArea
314*2d690920SAxel Dörfler void
315*2d690920SAxel Dörfler MessagingArea::SetNextArea(MessagingArea *area)
316*2d690920SAxel Dörfler {
317*2d690920SAxel Dörfler 	fNextArea = area;
318*2d690920SAxel Dörfler 	fHeader->next_kernel_area = (fNextArea ? fNextArea->ID() : -1);
319*2d690920SAxel Dörfler }
320*2d690920SAxel Dörfler 
321*2d690920SAxel Dörfler // NextArea
322*2d690920SAxel Dörfler MessagingArea *
323*2d690920SAxel Dörfler MessagingArea::NextArea() const
324*2d690920SAxel Dörfler {
325*2d690920SAxel Dörfler 	return fNextArea;
326*2d690920SAxel Dörfler }
327*2d690920SAxel Dörfler 
328*2d690920SAxel Dörfler // _CheckCommand
329*2d690920SAxel Dörfler messaging_command *
330*2d690920SAxel Dörfler MessagingArea::_CheckCommand(int32 offset, int32 &size)
331*2d690920SAxel Dörfler {
332*2d690920SAxel Dörfler 	// check offset
333*2d690920SAxel Dörfler 	if (offset < (int32)sizeof(messaging_area_header)
334*2d690920SAxel Dörfler 		|| offset + (int32)sizeof(messaging_command) > fSize
335*2d690920SAxel Dörfler 		|| (offset & 0x3)) {
336*2d690920SAxel Dörfler 		return NULL;
337*2d690920SAxel Dörfler 	}
338*2d690920SAxel Dörfler 
339*2d690920SAxel Dörfler 	// get and check size
340*2d690920SAxel Dörfler 	messaging_command *command = (messaging_command*)((char*)fHeader + offset);
341*2d690920SAxel Dörfler 	size = command->size;
342*2d690920SAxel Dörfler 	if (size < (int32)sizeof(messaging_command))
343*2d690920SAxel Dörfler 		return NULL;
344*2d690920SAxel Dörfler 	size = (size + 3) & 0x3;	// align
345*2d690920SAxel Dörfler 	if (offset + size > fSize)
346*2d690920SAxel Dörfler 		return NULL;
347*2d690920SAxel Dörfler 
348*2d690920SAxel Dörfler 	return command;
349*2d690920SAxel Dörfler }
350*2d690920SAxel Dörfler 
351*2d690920SAxel Dörfler 
352*2d690920SAxel Dörfler // #pragma mark -
353*2d690920SAxel Dörfler 
354*2d690920SAxel Dörfler // constructor
355*2d690920SAxel Dörfler MessagingService::MessagingService()
356*2d690920SAxel Dörfler 	: fLock("messaging service"),
357*2d690920SAxel Dörfler 	  fFirstArea(NULL),
358*2d690920SAxel Dörfler 	  fLastArea(NULL)
359*2d690920SAxel Dörfler {
360*2d690920SAxel Dörfler }
361*2d690920SAxel Dörfler 
362*2d690920SAxel Dörfler // destructor
363*2d690920SAxel Dörfler MessagingService::~MessagingService()
364*2d690920SAxel Dörfler {
365*2d690920SAxel Dörfler 	// Should actually never be called. Once created the service stays till the
366*2d690920SAxel Dörfler 	// bitter end.
367*2d690920SAxel Dörfler }
368*2d690920SAxel Dörfler 
369*2d690920SAxel Dörfler // InitCheck
370*2d690920SAxel Dörfler status_t
371*2d690920SAxel Dörfler MessagingService::InitCheck() const
372*2d690920SAxel Dörfler {
373*2d690920SAxel Dörfler 	if (fLock.Sem() < 0)
374*2d690920SAxel Dörfler 		return fLock.Sem();
375*2d690920SAxel Dörfler 	return B_OK;
376*2d690920SAxel Dörfler }
377*2d690920SAxel Dörfler 
378*2d690920SAxel Dörfler // Lock
379*2d690920SAxel Dörfler bool
380*2d690920SAxel Dörfler MessagingService::Lock()
381*2d690920SAxel Dörfler {
382*2d690920SAxel Dörfler 	return fLock.Lock();
383*2d690920SAxel Dörfler }
384*2d690920SAxel Dörfler 
385*2d690920SAxel Dörfler // Unlock
386*2d690920SAxel Dörfler void
387*2d690920SAxel Dörfler MessagingService::Unlock()
388*2d690920SAxel Dörfler {
389*2d690920SAxel Dörfler 	fLock.Unlock();
390*2d690920SAxel Dörfler }
391*2d690920SAxel Dörfler 
392*2d690920SAxel Dörfler // RegisterService
393*2d690920SAxel Dörfler status_t
394*2d690920SAxel Dörfler MessagingService::RegisterService(sem_id lockSem, sem_id counterSem,
395*2d690920SAxel Dörfler 	area_id &areaID)
396*2d690920SAxel Dörfler {
397*2d690920SAxel Dörfler 	// check, if a service is already registered
398*2d690920SAxel Dörfler 	if (fFirstArea)
399*2d690920SAxel Dörfler 		return B_BAD_VALUE;
400*2d690920SAxel Dörfler 
401*2d690920SAxel Dörfler 	status_t error = B_OK;
402*2d690920SAxel Dörfler 
403*2d690920SAxel Dörfler 	// check, if the semaphores are valid and belong to the calling team
404*2d690920SAxel Dörfler 	thread_info threadInfo;
405*2d690920SAxel Dörfler 	error = get_thread_info(find_thread(NULL), &threadInfo);
406*2d690920SAxel Dörfler 
407*2d690920SAxel Dörfler 	sem_info lockSemInfo;
408*2d690920SAxel Dörfler 	if (error == B_OK)
409*2d690920SAxel Dörfler 		error = get_sem_info(lockSem, &lockSemInfo);
410*2d690920SAxel Dörfler 
411*2d690920SAxel Dörfler 	sem_info counterSemInfo;
412*2d690920SAxel Dörfler 	if (error == B_OK)
413*2d690920SAxel Dörfler 		error = get_sem_info(counterSem, &counterSemInfo);
414*2d690920SAxel Dörfler 
415*2d690920SAxel Dörfler 	if (error != B_OK)
416*2d690920SAxel Dörfler 		return error;
417*2d690920SAxel Dörfler 
418*2d690920SAxel Dörfler 	if (threadInfo.team != lockSemInfo.team
419*2d690920SAxel Dörfler 		|| threadInfo.team != counterSemInfo.team) {
420*2d690920SAxel Dörfler 		return B_BAD_VALUE;
421*2d690920SAxel Dörfler 	}
422*2d690920SAxel Dörfler 
423*2d690920SAxel Dörfler 	// create an area
424*2d690920SAxel Dörfler 	fFirstArea = fLastArea = MessagingArea::Create(lockSem, counterSem);
425*2d690920SAxel Dörfler 	if (!fFirstArea)
426*2d690920SAxel Dörfler 		return B_NO_MEMORY;
427*2d690920SAxel Dörfler 
428*2d690920SAxel Dörfler 	areaID = fFirstArea->ID();
429*2d690920SAxel Dörfler 	fFirstArea->Unlock();
430*2d690920SAxel Dörfler 
431*2d690920SAxel Dörfler 	// store the server team and the semaphores
432*2d690920SAxel Dörfler 	fServerTeam = threadInfo.team;
433*2d690920SAxel Dörfler 	fLockSem = lockSem;
434*2d690920SAxel Dörfler 	fCounterSem = counterSem;
435*2d690920SAxel Dörfler 
436*2d690920SAxel Dörfler 	return B_OK;
437*2d690920SAxel Dörfler }
438*2d690920SAxel Dörfler 
439*2d690920SAxel Dörfler // UnregisterService
440*2d690920SAxel Dörfler status_t
441*2d690920SAxel Dörfler MessagingService::UnregisterService()
442*2d690920SAxel Dörfler {
443*2d690920SAxel Dörfler 	// check, if the team calling this function is indeed the server team
444*2d690920SAxel Dörfler 	thread_info threadInfo;
445*2d690920SAxel Dörfler 	status_t error = get_thread_info(find_thread(NULL), &threadInfo);
446*2d690920SAxel Dörfler 	if (error != B_OK)
447*2d690920SAxel Dörfler 		return error;
448*2d690920SAxel Dörfler 
449*2d690920SAxel Dörfler 	if (threadInfo.team != fServerTeam)
450*2d690920SAxel Dörfler 		return B_BAD_VALUE;
451*2d690920SAxel Dörfler 
452*2d690920SAxel Dörfler 	// delete all areas
453*2d690920SAxel Dörfler 	while (fFirstArea) {
454*2d690920SAxel Dörfler 		MessagingArea *area = fFirstArea;
455*2d690920SAxel Dörfler 		fFirstArea = area->NextArea();
456*2d690920SAxel Dörfler 		delete area;
457*2d690920SAxel Dörfler 	}
458*2d690920SAxel Dörfler 	fLastArea = NULL;
459*2d690920SAxel Dörfler 
460*2d690920SAxel Dörfler 	// unset the other members
461*2d690920SAxel Dörfler 	fLockSem = -1;
462*2d690920SAxel Dörfler 	fCounterSem -1;
463*2d690920SAxel Dörfler 	fServerTeam = -1;
464*2d690920SAxel Dörfler 
465*2d690920SAxel Dörfler 	return B_OK;
466*2d690920SAxel Dörfler }
467*2d690920SAxel Dörfler 
468*2d690920SAxel Dörfler // SendMessage
469*2d690920SAxel Dörfler status_t
470*2d690920SAxel Dörfler MessagingService::SendMessage(const void *message, int32 messageSize,
471*2d690920SAxel Dörfler 	const messaging_target *targets, int32 targetCount)
472*2d690920SAxel Dörfler {
473*2d690920SAxel Dörfler PRINT(("MessagingService::SendMessage(%p, %ld, %p, %ld)\n", message,
474*2d690920SAxel Dörfler messageSize, targets, targetCount));
475*2d690920SAxel Dörfler 	if (!message || messageSize <= 0 || !targets || targetCount <= 0)
476*2d690920SAxel Dörfler 		return B_BAD_VALUE;
477*2d690920SAxel Dörfler 
478*2d690920SAxel Dörfler 	int32 dataSize = sizeof(messaging_command_send_message)
479*2d690920SAxel Dörfler 		+ targetCount * sizeof(messaging_target) + messageSize;
480*2d690920SAxel Dörfler 
481*2d690920SAxel Dörfler 	// allocate space for the command
482*2d690920SAxel Dörfler 	MessagingArea *area;
483*2d690920SAxel Dörfler 	void *data;
484*2d690920SAxel Dörfler 	bool wasEmpty;
485*2d690920SAxel Dörfler 	status_t error = _AllocateCommand(MESSAGING_COMMAND_SEND_MESSAGE, dataSize,
486*2d690920SAxel Dörfler 		area, data, wasEmpty);
487*2d690920SAxel Dörfler 	if (error != B_OK) {
488*2d690920SAxel Dörfler 		PRINT(("MessagingService::SendMessage(): Failed to allocate space for "
489*2d690920SAxel Dörfler 			"send message command.\n"));
490*2d690920SAxel Dörfler 		return error;
491*2d690920SAxel Dörfler 	}
492*2d690920SAxel Dörfler PRINT(("  Allocated space for send message command: area: %p, data: %p, "
493*2d690920SAxel Dörfler "wasEmpty: %d\n", area, data, wasEmpty));
494*2d690920SAxel Dörfler 
495*2d690920SAxel Dörfler 	// prepare the command
496*2d690920SAxel Dörfler 	messaging_command_send_message *command
497*2d690920SAxel Dörfler 		= (messaging_command_send_message*)data;
498*2d690920SAxel Dörfler 	command->message_size = messageSize;
499*2d690920SAxel Dörfler 	command->target_count = targetCount;
500*2d690920SAxel Dörfler 	memcpy(command->targets, targets, sizeof(messaging_target) * targetCount);
501*2d690920SAxel Dörfler 	memcpy((char*)command + (dataSize - messageSize), message, messageSize);
502*2d690920SAxel Dörfler 
503*2d690920SAxel Dörfler 	// shoot
504*2d690920SAxel Dörfler 	area->Unlock();
505*2d690920SAxel Dörfler 	if (wasEmpty)
506*2d690920SAxel Dörfler 		area->CommitCommand();
507*2d690920SAxel Dörfler 
508*2d690920SAxel Dörfler 	return B_OK;
509*2d690920SAxel Dörfler }
510*2d690920SAxel Dörfler 
511*2d690920SAxel Dörfler // _AllocateCommand
512*2d690920SAxel Dörfler status_t
513*2d690920SAxel Dörfler MessagingService::_AllocateCommand(int32 commandWhat, int32 size,
514*2d690920SAxel Dörfler 	MessagingArea *&area, void *&data, bool &wasEmpty)
515*2d690920SAxel Dörfler {
516*2d690920SAxel Dörfler 	if (!fFirstArea)
517*2d690920SAxel Dörfler 		return B_NO_INIT;
518*2d690920SAxel Dörfler 
519*2d690920SAxel Dörfler 	if (!MessagingArea::CheckCommandSize(size))
520*2d690920SAxel Dörfler 		return B_BAD_VALUE;
521*2d690920SAxel Dörfler 
522*2d690920SAxel Dörfler 	// delete the discarded areas (save one)
523*2d690920SAxel Dörfler 	ObjectDeleter<MessagingArea> discardedAreaDeleter;
524*2d690920SAxel Dörfler 	MessagingArea *discardedArea = NULL;
525*2d690920SAxel Dörfler 	while (fFirstArea != fLastArea) {
526*2d690920SAxel Dörfler 		area = fFirstArea;
527*2d690920SAxel Dörfler 		area->Lock();
528*2d690920SAxel Dörfler 		if (area->Size() != 0) {
529*2d690920SAxel Dörfler 			area->Unlock();
530*2d690920SAxel Dörfler 			break;
531*2d690920SAxel Dörfler 		}
532*2d690920SAxel Dörfler 
533*2d690920SAxel Dörfler 		PRINT(("MessagingService::_AllocateCommand(): Discarding area: %p\n",
534*2d690920SAxel Dörfler 			area));
535*2d690920SAxel Dörfler 
536*2d690920SAxel Dörfler 		fFirstArea = area->NextArea();
537*2d690920SAxel Dörfler 		area->SetNextArea(NULL);
538*2d690920SAxel Dörfler 		discardedArea = area;
539*2d690920SAxel Dörfler 		discardedAreaDeleter.SetTo(area);
540*2d690920SAxel Dörfler 	}
541*2d690920SAxel Dörfler 
542*2d690920SAxel Dörfler 	// allocate space for the command in the last area
543*2d690920SAxel Dörfler 	area = fLastArea;
544*2d690920SAxel Dörfler 	area->Lock();
545*2d690920SAxel Dörfler 	data = area->AllocateCommand(commandWhat, size, wasEmpty);
546*2d690920SAxel Dörfler 
547*2d690920SAxel Dörfler 	if (!data) {
548*2d690920SAxel Dörfler 		// not enough space in the last area: create a new area or reuse a
549*2d690920SAxel Dörfler 		// discarded one
550*2d690920SAxel Dörfler 		if (discardedArea) {
551*2d690920SAxel Dörfler 			area = discardedAreaDeleter.Detach();
552*2d690920SAxel Dörfler 			area->InitHeader();
553*2d690920SAxel Dörfler 			PRINT(("MessagingService::_AllocateCommand(): Not enough space "
554*2d690920SAxel Dörfler 				"left in current area. Recycling discarded one: %p\n", area));
555*2d690920SAxel Dörfler 		} else {
556*2d690920SAxel Dörfler 			area = MessagingArea::Create(fLockSem, fCounterSem);
557*2d690920SAxel Dörfler 			PRINT(("MessagingService::_AllocateCommand(): Not enough space "
558*2d690920SAxel Dörfler 				"left in current area. Allocated new one: %p\n", area));
559*2d690920SAxel Dörfler 		}
560*2d690920SAxel Dörfler 		if (!area) {
561*2d690920SAxel Dörfler 			fLastArea->Unlock();
562*2d690920SAxel Dörfler 			return B_NO_MEMORY;
563*2d690920SAxel Dörfler 		}
564*2d690920SAxel Dörfler 
565*2d690920SAxel Dörfler 		// add the new area
566*2d690920SAxel Dörfler 		fLastArea->SetNextArea(area);
567*2d690920SAxel Dörfler 		fLastArea->Unlock();
568*2d690920SAxel Dörfler 		fLastArea = area;
569*2d690920SAxel Dörfler 
570*2d690920SAxel Dörfler 		// allocate space for the command
571*2d690920SAxel Dörfler 		data = area->AllocateCommand(commandWhat, size, wasEmpty);
572*2d690920SAxel Dörfler 
573*2d690920SAxel Dörfler 		if (!data) {
574*2d690920SAxel Dörfler 			// that should never happen
575*2d690920SAxel Dörfler 			area->Unlock();
576*2d690920SAxel Dörfler 			return B_NO_MEMORY;
577*2d690920SAxel Dörfler 		}
578*2d690920SAxel Dörfler 	}
579*2d690920SAxel Dörfler 
580*2d690920SAxel Dörfler 	return B_OK;
581*2d690920SAxel Dörfler }
582*2d690920SAxel Dörfler 
583