1b93d2480SAxel Dörfler/*
2798ad3dbSAxel Dörfler * Copyright 2001-2015 Haiku, Inc. All rights reserved
3b93d2480SAxel Dörfler * Distributed under the terms of the MIT License.
4b93d2480SAxel Dörfler *
5b93d2480SAxel Dörfler * Authors:
6be902ac4SJohn Scipione *		DarkWyrm, bpmagic@columbus.rr.com
7b93d2480SAxel Dörfler *		Axel D��rfler, axeld@pinc-software.de
8be902ac4SJohn Scipione *		Erik Jaesler, erik@cgsoftware.com
9be902ac4SJohn Scipione *		Ingo Weinhold, bonefish@@users.sf.net
10b93d2480SAxel Dörfler */
11b93d2480SAxel Dörfler
12edbfa1c7SAxel Dörfler
13be902ac4SJohn Scipione// BLooper class spawns a thread that runs a message loop.
1452a38012Sejakowatz
15edbfa1c7SAxel Dörfler
16446d4dcaSAxel Dörfler#include <Looper.h>
17446d4dcaSAxel Dörfler
18446d4dcaSAxel Dörfler#include <new>
19446d4dcaSAxel Dörfler#include <stdio.h>
20446d4dcaSAxel Dörfler#include <stdlib.h>
21c01f349eSAxel Dörfler
22c01f349eSAxel Dörfler#include <Autolock.h>
23c01f349eSAxel Dörfler#include <Message.h>
24c01f349eSAxel Dörfler#include <MessageFilter.h>
25c01f349eSAxel Dörfler#include <MessageQueue.h>
26c01f349eSAxel Dörfler#include <Messenger.h>
27c01f349eSAxel Dörfler#include <PropertyInfo.h>
28c01f349eSAxel Dörfler
29446d4dcaSAxel Dörfler#include <AppMisc.h>
30446d4dcaSAxel Dörfler#include <AutoLocker.h>
31446d4dcaSAxel Dörfler#include <DirectMessageTarget.h>
32446d4dcaSAxel Dörfler#include <LooperList.h>
33446d4dcaSAxel Dörfler#include <MessagePrivate.h>
34446d4dcaSAxel Dörfler#include <TokenSpace.h>
3552a38012Sejakowatz
3652a38012Sejakowatz
3752a38012Sejakowatz// debugging
3852a38012Sejakowatz//#define DBG(x) x
39c5c962d4SIngo Weinhold#define DBG(x)	;
40c5c962d4SIngo Weinhold#define PRINT(x)	DBG({ printf("[%6ld] ", find_thread(NULL)); printf x; })
4152a38012Sejakowatz
42bcab07adSIngo Weinhold/*
43bcab07adSIngo Weinhold#include <Autolock.h>
44bcab07adSIngo Weinhold#include <Locker.h>
45bcab07adSIngo Weinholdstatic BLocker sDebugPrintLocker("BLooper debug print");
46bcab07adSIngo Weinhold#define PRINT(x)	DBG({						\
47bcab07adSIngo Weinhold	BAutolock _(sDebugPrintLocker);				\
48bcab07adSIngo Weinhold	debug_printf("[%6ld] ", find_thread(NULL));	\
49bcab07adSIngo Weinhold	debug_printf x;								\
50bcab07adSIngo Weinhold})
51bcab07adSIngo Weinhold*/
52bcab07adSIngo Weinhold
53683be71eSAxel Dörfler
5452a38012Sejakowatz#define FILTER_LIST_BLOCK_SIZE	5
5552a38012Sejakowatz#define DATA_BLOCK_SIZE			5
5652a38012Sejakowatz
57edbfa1c7SAxel Dörfler
5852a38012Sejakowatzusing BPrivate::gDefaultTokens;
59abb57933Sejakowatzusing BPrivate::gLooperList;
60abb57933Sejakowatzusing BPrivate::BLooperList;
6152a38012Sejakowatz
6252a38012Sejakowatzport_id _get_looper_port_(const BLooper* looper);
6352a38012Sejakowatz
643cd9c864SAxel Dörflerenum {
652e2e159aSejakowatz	BLOOPER_PROCESS_INTERNALLY = 0,
662e2e159aSejakowatz	BLOOPER_HANDLER_BY_INDEX
672e2e159aSejakowatz};
682e2e159aSejakowatz
69edbfa1c7SAxel Dörflerstatic property_info sLooperPropInfo[] = {
70ec9673bfSejakowatz	{
71b1698c8eSejakowatz		"Handler",
72ec9673bfSejakowatz			{},
73ec9673bfSejakowatz			{B_INDEX_SPECIFIER, B_REVERSE_INDEX_SPECIFIER},
742e2e159aSejakowatz			NULL, BLOOPER_HANDLER_BY_INDEX,
75ec9673bfSejakowatz			{},
76ec9673bfSejakowatz			{},
77ec9673bfSejakowatz			{}
78ec9673bfSejakowatz	},
79ec9673bfSejakowatz	{
80b1698c8eSejakowatz		"Handlers",
81ec9673bfSejakowatz			{B_GET_PROPERTY},
82ec9673bfSejakowatz			{B_DIRECT_SPECIFIER},
832e2e159aSejakowatz			NULL, BLOOPER_PROCESS_INTERNALLY,
84ec9673bfSejakowatz			{B_MESSENGER_TYPE},
85ec9673bfSejakowatz			{},
86ec9673bfSejakowatz			{}
87ec9673bfSejakowatz	},
88ec9673bfSejakowatz	{
89b1698c8eSejakowatz		"Handler",
90ec9673bfSejakowatz			{B_COUNT_PROPERTIES},
91ec9673bfSejakowatz			{B_DIRECT_SPECIFIER},
922e2e159aSejakowatz			NULL, BLOOPER_PROCESS_INTERNALLY,
93ec9673bfSejakowatz			{B_INT32_TYPE},
94ec9673bfSejakowatz			{},
95ec9673bfSejakowatz			{}
96ec9673bfSejakowatz	},
9716af9b4cSHumdinger
9816af9b4cSHumdinger	{ 0 }
9952a38012Sejakowatz};
10052a38012Sejakowatz
1013cd9c864SAxel Dörflerstruct _loop_data_ {
10252a38012Sejakowatz	BLooper*	looper;
10352a38012Sejakowatz	thread_id	thread;
10452a38012Sejakowatz};
10552a38012Sejakowatz
1063cd9c864SAxel Dörfler
1073cd9c864SAxel Dörfler//	#pragma mark -
1083cd9c864SAxel Dörfler
1093cd9c864SAxel Dörfler
1108417b8d8SAxel DörflerBLooper::BLooper(const char* name, int32 priority, int32 portCapacity)
111be902ac4SJohn Scipione	:
112be902ac4SJohn Scipione	BHandler(name)
11352a38012Sejakowatz{
1141480e5daSAxel Dörfler	_InitData(name, priority, -1, portCapacity);
11552a38012Sejakowatz}
1163cd9c864SAxel Dörfler
1173cd9c864SAxel Dörfler
11852a38012SejakowatzBLooper::~BLooper()
11952a38012Sejakowatz{
1203cd9c864SAxel Dörfler	if (fRunCalled && !fTerminating) {
121ec9673bfSejakowatz		debugger("You can't call delete on a BLooper object "
1228417b8d8SAxel Dörfler			"once it is running.");
123ec9673bfSejakowatz	}
124ec9673bfSejakowatz
125abb57933Sejakowatz	Lock();
1266a757163SIngo Weinhold
127ff1ade6bSejakowatz	// In case the looper thread calls Quit() fLastMessage is not deleted.
1283cd9c864SAxel Dörfler	if (fLastMessage) {
129ff1ade6bSejakowatz		delete fLastMessage;
130ff1ade6bSejakowatz		fLastMessage = NULL;
131ff1ade6bSejakowatz	}
132ff1ade6bSejakowatz
133ff1ade6bSejakowatz	// Close the message port and read and reply to the remaining messages.
134798ad3dbSAxel Dörfler	if (fMsgPort >= 0 && fOwnsPort)
135ff1ade6bSejakowatz		close_port(fMsgPort);
136ff1ade6bSejakowatz
137ff1ade6bSejakowatz	// Clear the queue so our call to IsMessageWaiting() below doesn't give
138ff1ade6bSejakowatz	// us bogus info
1399dbe170aSAxel Dörfler	fDirectTarget->Close();
1409dbe170aSAxel Dörfler
1418417b8d8SAxel Dörfler	BMessage* message;
1429dbe170aSAxel Dörfler	while ((message = fDirectTarget->Queue()->NextMessage()) != NULL) {
143c01f349eSAxel Dörfler		delete message;
144c01f349eSAxel Dörfler			// msg will automagically post generic reply
145ff1ade6bSejakowatz	}
1466a757163SIngo Weinhold
1477d407a1eSAugustin Cavalier	if (fOwnsPort) {
148798ad3dbSAxel Dörfler		do {
149798ad3dbSAxel Dörfler			delete ReadMessageFromPort(0);
150798ad3dbSAxel Dörfler				// msg will automagically post generic reply
151798ad3dbSAxel Dörfler		} while (IsMessageWaiting());
1526a757163SIngo Weinhold
153798ad3dbSAxel Dörfler		delete_port(fMsgPort);
154798ad3dbSAxel Dörfler	}
1559dbe170aSAxel Dörfler	fDirectTarget->Release();
15652a38012Sejakowatz
15752a38012Sejakowatz	// Clean up our filters
15852a38012Sejakowatz	SetCommonFilterList(NULL);
15952a38012Sejakowatz
1602b2ec438SIngo Weinhold	AutoLocker<BLooperList> ListLock(gLooperList);
16152a38012Sejakowatz	RemoveHandler(this);
162ff1ade6bSejakowatz
163ff1ade6bSejakowatz	// Remove all the "child" handlers
164f72ed717SStephan Aßmus	int32 count = fHandlers.CountItems();
165f72ed717SStephan Aßmus	for (int32 i = 0; i < count; i++) {
166f72ed717SStephan Aßmus		BHandler* handler = (BHandler*)fHandlers.ItemAtFast(i);
167f72ed717SStephan Aßmus		handler->SetNextHandler(NULL);
168f72ed717SStephan Aßmus		handler->SetLooper(NULL);
169ff1ade6bSejakowatz	}
170f72ed717SStephan Aßmus	fHandlers.MakeEmpty();
171ff1ade6bSejakowatz
172837261c6SAxel Dörfler	Unlock();
173c01f349eSAxel Dörfler	gLooperList.RemoveLooper(this);
174cb5b0f6dSejakowatz	delete_sem(fLockSem);
17552a38012Sejakowatz}
1763cd9c864SAxel Dörfler
1773cd9c864SAxel Dörfler
1788417b8d8SAxel DörflerBLooper::BLooper(BMessage* data)
1793cd9c864SAxel Dörfler	: BHandler(data)
18052a38012Sejakowatz{
1813cd9c864SAxel Dörfler	int32 portCapacity;
1828417b8d8SAxel Dörfler	if (data->FindInt32("_port_cap", &portCapacity) != B_OK || portCapacity < 0)
1833cd9c864SAxel Dörfler		portCapacity = B_LOOPER_PORT_DEFAULT_CAPACITY;
18452a38012Sejakowatz
185d2805ca9SKarsten Heimrich	int32 priority;
186d2805ca9SKarsten Heimrich	if (data->FindInt32("_prio", &priority) != B_OK)
187d2805ca9SKarsten Heimrich		priority = B_NORMAL_PRIORITY;
188d2805ca9SKarsten Heimrich
1891480e5daSAxel Dörfler	_InitData(Name(), priority, -1, portCapacity);
19052a38012Sejakowatz}
1913cd9c864SAxel Dörfler
1923cd9c864SAxel Dörfler
1938417b8d8SAxel DörflerBArchivable*
1948417b8d8SAxel DörflerBLooper::Instantiate(BMessage* data)
19552a38012Sejakowatz{
19652a38012Sejakowatz	if (validate_instantiation(data, "BLooper"))
19752a38012Sejakowatz		return new BLooper(data);
19852a38012Sejakowatz
19952a38012Sejakowatz	return NULL;
20052a38012Sejakowatz}
2013cd9c864SAxel Dörfler
2023cd9c864SAxel Dörfler
2033cd9c864SAxel Dörflerstatus_t
2048417b8d8SAxel DörflerBLooper::Archive(BMessage* data, bool deep) const
20552a38012Sejakowatz{
2063cd9c864SAxel Dörfler	status_t status = BHandler::Archive(data, deep);
2073cd9c864SAxel Dörfler	if (status < B_OK)
2083cd9c864SAxel Dörfler		return status;
20952a38012Sejakowatz
2103cd9c864SAxel Dörfler	port_info info;
2113cd9c864SAxel Dörfler	status = get_port_info(fMsgPort, &info);
2123cd9c864SAxel Dörfler	if (status == B_OK)
2133cd9c864SAxel Dörfler		status = data->AddInt32("_port_cap", info.capacity);
2143cd9c864SAxel Dörfler
215d2805ca9SKarsten Heimrich	thread_info threadInfo;
216d2805ca9SKarsten Heimrich	if (get_thread_info(Thread(), &threadInfo) == B_OK)
217d2805ca9SKarsten Heimrich		status = data->AddInt32("_prio", threadInfo.priority);
218c01f349eSAxel Dörfler
2193cd9c864SAxel Dörfler	return status;
22052a38012Sejakowatz}
2213cd9c864SAxel Dörfler
2223cd9c864SAxel Dörfler
2233cd9c864SAxel Dörflerstatus_t
2243cd9c864SAxel DörflerBLooper::PostMessage(uint32 command)
22552a38012Sejakowatz{
2263cd9c864SAxel Dörfler	BMessage message(command);
2273cd9c864SAxel Dörfler	return _PostMessage(&message, this, NULL);
22852a38012Sejakowatz}
2293cd9c864SAxel Dörfler
2303cd9c864SAxel Dörfler
2313cd9c864SAxel Dörflerstatus_t
2328417b8d8SAxel DörflerBLooper::PostMessage(BMessage* message)
23352a38012Sejakowatz{
23452a38012Sejakowatz	return _PostMessage(message, this, NULL);
23552a38012Sejakowatz}
2363cd9c864SAxel Dörfler
2373cd9c864SAxel Dörfler
2383cd9c864SAxel Dörflerstatus_t
2398417b8d8SAxel DörflerBLooper::PostMessage(uint32 command, BHandler* handler, BHandler* replyTo)
24052a38012Sejakowatz{
2413cd9c864SAxel Dörfler	BMessage message(command);
2423cd9c864SAxel Dörfler	return _PostMessage(&message, handler, replyTo);
24352a38012Sejakowatz}
2443cd9c864SAxel Dörfler
2453cd9c864SAxel Dörfler
2463cd9c864SAxel Dörflerstatus_t
2478417b8d8SAxel DörflerBLooper::PostMessage(BMessage* message, BHandler* handler, BHandler* replyTo)
24852a38012Sejakowatz{
2493cd9c864SAxel Dörfler	return _PostMessage(message, handler, replyTo);
25052a38012Sejakowatz}
2513cd9c864SAxel Dörfler
2523cd9c864SAxel Dörfler
2533cd9c864SAxel Dörflervoid
2548417b8d8SAxel DörflerBLooper::DispatchMessage(BMessage* message, BHandler* handler)
2553cd9c864SAxel Dörfler{
2563cd9c864SAxel Dörfler	PRINT(("BLooper::DispatchMessage(%.4s)\n", (char*)&message->what));
257c01f349eSAxel Dörfler
2583cd9c864SAxel Dörfler	switch (message->what) {
25952a38012Sejakowatz		case _QUIT_:
26052a38012Sejakowatz			// Can't call Quit() to do this, because of the slight chance
26152a38012Sejakowatz			// another thread with have us locked between now and then.
26252a38012Sejakowatz			fTerminating = true;
2633cd9c864SAxel Dörfler
2643cd9c864SAxel Dörfler			// After returning from DispatchMessage(), the looper will be
2653cd9c864SAxel Dörfler			// deleted in _task0_()
26652a38012Sejakowatz			break;
26752a38012Sejakowatz
26852a38012Sejakowatz		case B_QUIT_REQUESTED:
2693cd9c864SAxel Dörfler			if (handler == this) {
27014d02d22SAxel Dörfler				_QuitRequested(message);
27152a38012Sejakowatz				break;
27252a38012Sejakowatz			}
2733cd9c864SAxel Dörfler
2743cd9c864SAxel Dörfler			// fall through
27552a38012Sejakowatz
27652a38012Sejakowatz		default:
27752a38012Sejakowatz			handler->MessageReceived(message);
27852a38012Sejakowatz			break;
27952a38012Sejakowatz	}
2803cd9c864SAxel Dörfler	PRINT(("BLooper::DispatchMessage() done\n"));
28152a38012Sejakowatz}
2823cd9c864SAxel Dörfler
2833cd9c864SAxel Dörfler
2843cd9c864SAxel Dörflervoid
2858417b8d8SAxel DörflerBLooper::MessageReceived(BMessage* message)
28652a38012Sejakowatz{
287c01f349eSAxel Dörfler	// TODO: implement scripting support
2888417b8d8SAxel Dörfler	BHandler::MessageReceived(message);
28952a38012Sejakowatz}
290410d5c37SAxel Dörfler
291410d5c37SAxel Dörfler
292410d5c37SAxel DörflerBMessage*
293410d5c37SAxel DörflerBLooper::CurrentMessage() const
29452a38012Sejakowatz{
29552a38012Sejakowatz	return fLastMessage;
29652a38012Sejakowatz}
297410d5c37SAxel Dörfler
298410d5c37SAxel Dörfler
299410d5c37SAxel DörflerBMessage*
300410d5c37SAxel DörflerBLooper::DetachCurrentMessage()
30152a38012Sejakowatz{
3028417b8d8SAxel Dörfler	BMessage* message = fLastMessage;
30352a38012Sejakowatz	fLastMessage = NULL;
3048417b8d8SAxel Dörfler	return message;
30552a38012Sejakowatz}
306410d5c37SAxel Dörfler
307410d5c37SAxel Dörfler
3085d7f782dSIngo Weinholdvoid
3095d7f782dSIngo WeinholdBLooper::DispatchExternalMessage(BMessage* message, BHandler* handler,
3105d7f782dSIngo Weinhold	bool& _detached)
3115d7f782dSIngo Weinhold{
3125d7f782dSIngo Weinhold	AssertLocked();
3135d7f782dSIngo Weinhold
3145d7f782dSIngo Weinhold	BMessage* previousMessage = fLastMessage;
3155d7f782dSIngo Weinhold	fLastMessage = message;
3165d7f782dSIngo Weinhold
3175d7f782dSIngo Weinhold	DispatchMessage(message, handler);
3185d7f782dSIngo Weinhold
3195d7f782dSIngo Weinhold	_detached = fLastMessage == NULL;
3205d7f782dSIngo Weinhold	fLastMessage = previousMessage;
3215d7f782dSIngo Weinhold}
3225d7f782dSIngo Weinhold
3235d7f782dSIngo Weinhold
324410d5c37SAxel DörflerBMessageQueue*
325410d5c37SAxel DörflerBLooper::MessageQueue() const
32652a38012Sejakowatz{
3279dbe170aSAxel Dörfler	return fDirectTarget->Queue();
32852a38012Sejakowatz}
329410d5c37SAxel Dörfler
330410d5c37SAxel Dörfler
331410d5c37SAxel Dörflerbool
332410d5c37SAxel DörflerBLooper::IsMessageWaiting() const
33352a38012Sejakowatz{
334410d5c37SAxel Dörfler	AssertLocked();
33552a38012Sejakowatz
3369dbe170aSAxel Dörfler	if (!fDirectTarget->Queue()->IsEmpty())
33752a38012Sejakowatz		return true;
33852a38012Sejakowatz
33952a38012Sejakowatz	int32 count;
340410d5c37SAxel Dörfler	do {
3413339a96bSAxel Dörfler		count = port_buffer_size_etc(fMsgPort, B_RELATIVE_TIMEOUT, 0);
342865f9d8eSejakowatz	} while (count == B_INTERRUPTED);
34352a38012Sejakowatz
34452a38012Sejakowatz	return count > 0;
34552a38012Sejakowatz}
346410d5c37SAxel Dörfler
347410d5c37SAxel Dörfler
348410d5c37SAxel Dörflervoid
349410d5c37SAxel DörflerBLooper::AddHandler(BHandler* handler)
35052a38012Sejakowatz{
351410d5c37SAxel Dörfler	if (handler == NULL)
35219ba51b7Sejakowatz		return;
35319ba51b7Sejakowatz
354410d5c37SAxel Dörfler	AssertLocked();
35552a38012Sejakowatz
356410d5c37SAxel Dörfler	if (handler->Looper() == NULL) {
35752a38012Sejakowatz		fHandlers.AddItem(handler);
35852a38012Sejakowatz		handler->SetLooper(this);
359822cdddbSIngo Weinhold		if (handler != this)	// avoid a cycle
360822cdddbSIngo Weinhold			handler->SetNextHandler(this);
36152a38012Sejakowatz	}
36252a38012Sejakowatz}
363410d5c37SAxel Dörfler
364410d5c37SAxel Dörfler
365410d5c37SAxel Dörflerbool
366410d5c37SAxel DörflerBLooper::RemoveHandler(BHandler* handler)
36752a38012Sejakowatz{
368410d5c37SAxel Dörfler	if (handler == NULL)
369abb57933Sejakowatz		return false;
370abb57933Sejakowatz
371410d5c37SAxel Dörfler	AssertLocked();
37252a38012Sejakowatz
373410d5c37SAxel Dörfler	if (handler->Looper() == this && fHandlers.RemoveItem(handler)) {
37452a38012Sejakowatz		if (handler == fPreferred)
37552a38012Sejakowatz			fPreferred = NULL;
37652a38012Sejakowatz
37752a38012Sejakowatz		handler->SetNextHandler(NULL);
37852a38012Sejakowatz		handler->SetLooper(NULL);
37952a38012Sejakowatz		return true;
38052a38012Sejakowatz	}
38152a38012Sejakowatz
38252a38012Sejakowatz	return false;
38352a38012Sejakowatz}
384410d5c37SAxel Dörfler
385410d5c37SAxel Dörfler
386410d5c37SAxel Dörflerint32
387410d5c37SAxel DörflerBLooper::CountHandlers() const
38852a38012Sejakowatz{
38952a38012Sejakowatz	AssertLocked();
39052a38012Sejakowatz
39152a38012Sejakowatz	return fHandlers.CountItems();
39252a38012Sejakowatz}
393410d5c37SAxel Dörfler
394410d5c37SAxel Dörfler
395410d5c37SAxel DörflerBHandler*
396410d5c37SAxel DörflerBLooper::HandlerAt(int32 index) const
39752a38012Sejakowatz{
398410d5c37SAxel Dörfler	AssertLocked();
39952a38012Sejakowatz
40052a38012Sejakowatz	return (BHandler*)fHandlers.ItemAt(index);
40152a38012Sejakowatz}
402410d5c37SAxel Dörfler
403410d5c37SAxel Dörfler
404410d5c37SAxel Dörflerint32
405410d5c37SAxel DörflerBLooper::IndexOf(BHandler* handler) const
40652a38012Sejakowatz{
407410d5c37SAxel Dörfler	AssertLocked();
40852a38012Sejakowatz
40952a38012Sejakowatz	return fHandlers.IndexOf(handler);
41052a38012Sejakowatz}
411410d5c37SAxel Dörfler
412410d5c37SAxel Dörfler
413410d5c37SAxel DörflerBHandler*
414410d5c37SAxel DörflerBLooper::PreferredHandler() const
41552a38012Sejakowatz{
41652a38012Sejakowatz	return fPreferred;
41752a38012Sejakowatz}
418410d5c37SAxel Dörfler
419410d5c37SAxel Dörfler
420410d5c37SAxel Dörflervoid
421410d5c37SAxel DörflerBLooper::SetPreferredHandler(BHandler* handler)
42252a38012Sejakowatz{
423410d5c37SAxel Dörfler	if (handler && handler->Looper() == this && IndexOf(handler) >= 0) {
42452a38012Sejakowatz		fPreferred = handler;
425410d5c37SAxel Dörfler	} else {
42652a38012Sejakowatz		fPreferred = NULL;
42752a38012Sejakowatz	}
42852a38012Sejakowatz}
4293cd9c864SAxel Dörfler
4303cd9c864SAxel Dörfler
4313cd9c864SAxel Dörflerthread_id
4323cd9c864SAxel DörflerBLooper::Run()
43352a38012Sejakowatz{
43452a38012Sejakowatz	AssertLocked();
43552a38012Sejakowatz
4363cd9c864SAxel Dörfler	if (fRunCalled) {
43752a38012Sejakowatz		// Not allowed to call Run() more than once
438ec9673bfSejakowatz		debugger("can't call BLooper::Run twice!");
439c01f349eSAxel Dörfler		return fThread;
44052a38012Sejakowatz	}
44152a38012Sejakowatz
442c01f349eSAxel Dörfler	fThread = spawn_thread(_task0_, Name(), fInitPriority, this);
443c01f349eSAxel Dörfler	if (fThread < B_OK)
444c01f349eSAxel Dörfler		return fThread;
44552a38012Sejakowatz
4463cd9c864SAxel Dörfler	if (fMsgPort < B_OK)
44752a38012Sejakowatz		return fMsgPort;
44852a38012Sejakowatz
44952a38012Sejakowatz	fRunCalled = true;
45052a38012Sejakowatz	Unlock();
4513cd9c864SAxel Dörfler
452c01f349eSAxel Dörfler	status_t err = resume_thread(fThread);
4533cd9c864SAxel Dörfler	if (err < B_OK)
45452a38012Sejakowatz		return err;
45552a38012Sejakowatz
456c01f349eSAxel Dörfler	return fThread;
45752a38012Sejakowatz}
4583cd9c864SAxel Dörfler
4593cd9c864SAxel Dörfler
460151343ebSAdrien Destuguesvoid
461151343ebSAdrien DestuguesBLooper::Loop()
462151343ebSAdrien Destugues{
463151343ebSAdrien Destugues	AssertLocked();
464151343ebSAdrien Destugues
465151343ebSAdrien Destugues	if (fRunCalled) {
466151343ebSAdrien Destugues		// Not allowed to call Loop() or Run() more than once
467151343ebSAdrien Destugues		debugger("can't call BLooper::Loop twice!");
468151343ebSAdrien Destugues		return;
469151343ebSAdrien Destugues	}
470151343ebSAdrien Destugues
471151343ebSAdrien Destugues	fThread = find_thread(NULL);
472151343ebSAdrien Destugues	fRunCalled = true;
473151343ebSAdrien Destugues
474151343ebSAdrien Destugues	task_looper();
475151343ebSAdrien Destugues}
476151343ebSAdrien Destugues
477151343ebSAdrien Destugues
4783cd9c864SAxel Dörflervoid
4793cd9c864SAxel DörflerBLooper::Quit()
48052a38012Sejakowatz{
4813cd9c864SAxel Dörfler	PRINT(("BLooper::Quit()\n"));
4823cd9c864SAxel Dörfler
4833cd9c864SAxel Dörfler	if (!IsLocked()) {
48452a38012Sejakowatz		printf("ERROR - you must Lock a looper before calling Quit(), "
4859be774b5SAlex Smith			"team=%" B_PRId32 ", looper=%s\n", Team(),
4869be774b5SAlex Smith			Name() ? Name() : "unnamed");
48752a38012Sejakowatz	}
4887bf6c069Sejakowatz
4897bf6c069Sejakowatz	// Try to lock
4903cd9c864SAxel Dörfler	if (!Lock()) {
4917bf6c069Sejakowatz		// We're toast already
4927bf6c069Sejakowatz		return;
4937bf6c069Sejakowatz	}
4947bf6c069Sejakowatz
4953cd9c864SAxel Dörfler	PRINT(("  is locked\n"));
49652a38012Sejakowatz
497410d5c37SAxel Dörfler	if (!fRunCalled) {
4983cd9c864SAxel Dörfler		PRINT(("  Run() has not been called yet\n"));
49952a38012Sejakowatz		fTerminating = true;
50052a38012Sejakowatz		delete this;
501c01f349eSAxel Dörfler	} else if (find_thread(NULL) == fThread) {
5023cd9c864SAxel Dörfler		PRINT(("  We are the looper thread\n"));
503c26a5ceaSIngo Weinhold		fTerminating = true;
504c26a5ceaSIngo Weinhold		delete this;
505c26a5ceaSIngo Weinhold		exit_thread(0);
5063cd9c864SAxel Dörfler	} else {
5073cd9c864SAxel Dörfler		PRINT(("  Run() has already been called and we are not the looper thread\n"));
5083cd9c864SAxel Dörfler
50952a38012Sejakowatz		// As with sem in _Lock(), we need to cache this here in case the looper
51052a38012Sejakowatz		// disappears before we get to the wait_for_thread() below
511616e68e7SAxel Dörfler		thread_id thread = Thread();
51252a38012Sejakowatz
5133cd9c864SAxel Dörfler		// We need to unlock here. Otherwise the looper thread can't
51452a38012Sejakowatz		// dispatch the _QUIT_ message we're going to post.
515cb5b0f6dSejakowatz		UnlockFully();
51652a38012Sejakowatz
51752a38012Sejakowatz		// As per the BeBook, if we've been called by a thread other than
51852a38012Sejakowatz		// our own, the rest of the message queue has to get processed.  So
51952a38012Sejakowatz		// we put this in the queue, and when it shows up, we'll call Quit()
52052a38012Sejakowatz		// from our own thread.
521616e68e7SAxel Dörfler		// QuitRequested() will not be called in this case.
522616e68e7SAxel Dörfler		PostMessage(_QUIT_);
52352a38012Sejakowatz
5248417b8d8SAxel Dörfler		// We have to wait until the looper is done processing any remaining
5258417b8d8SAxel Dörfler		// messages.
526616e68e7SAxel Dörfler		status_t status;
527616e68e7SAxel Dörfler		while (wait_for_thread(thread, &status) == B_INTERRUPTED)
5283cd9c864SAxel Dörfler			;
52952a38012Sejakowatz	}
5303cd9c864SAxel Dörfler
5313cd9c864SAxel Dörfler	PRINT(("BLooper::Quit() done\n"));
53252a38012Sejakowatz}
5333cd9c864SAxel Dörfler
5343cd9c864SAxel Dörfler
5353cd9c864SAxel Dörflerbool
5363cd9c864SAxel DörflerBLooper::QuitRequested()
53752a38012Sejakowatz{
53852a38012Sejakowatz	return true;
53952a38012Sejakowatz}
5403cd9c864SAxel Dörfler
5413cd9c864SAxel Dörfler
5423cd9c864SAxel Dörflerbool
5433cd9c864SAxel DörflerBLooper::Lock()
54452a38012Sejakowatz{
54552a38012Sejakowatz	// Defer to global _Lock(); see notes there
54652a38012Sejakowatz	return _Lock(this, -1, B_INFINITE_TIMEOUT) == B_OK;
54752a38012Sejakowatz}
548410d5c37SAxel Dörfler
549410d5c37SAxel Dörfler
550410d5c37SAxel Dörflervoid
551410d5c37SAxel DörflerBLooper::Unlock()
55252a38012Sejakowatz{
553c5c962d4SIngo WeinholdPRINT(("BLooper::Unlock()\n"));
55452a38012Sejakowatz	//	Make sure we're locked to begin with
55552a38012Sejakowatz	AssertLocked();
55652a38012Sejakowatz
55752a38012Sejakowatz	//	Decrement fOwnerCount
55852a38012Sejakowatz	--fOwnerCount;
559c5c962d4SIngo WeinholdPRINT(("  fOwnerCount now: %ld\n", fOwnerCount));
56052a38012Sejakowatz	//	Check to see if the owner still wants a lock
561410d5c37SAxel Dörfler	if (fOwnerCount == 0) {
56252a38012Sejakowatz		//	Set fOwner to invalid thread_id (< 0)
56352a38012Sejakowatz		fOwner = -1;
5641260fa65SAxel Dörfler		fCachedStack = 0;
56552a38012Sejakowatz
566791b9c21SStefano Ceccherini#if DEBUG < 1
56752a38012Sejakowatz		//	Decrement requested lock count (using fAtomicCount for this)
56868ead3eaSStefano Ceccherini		int32 atomicCount = atomic_add(&fAtomicCount, -1);
569c5c962d4SIngo WeinholdPRINT(("  fAtomicCount now: %ld\n", fAtomicCount));
57052a38012Sejakowatz
571791b9c21SStefano Ceccherini		// Check if anyone is waiting for a lock
572791b9c21SStefano Ceccherini		// and release if it's the case
573791b9c21SStefano Ceccherini		if (atomicCount > 1)
574791b9c21SStefano Ceccherini#endif
575d2805ca9SKarsten Heimrich			release_sem(fLockSem);
57652a38012Sejakowatz	}
577c5c962d4SIngo WeinholdPRINT(("BLooper::Unlock() done\n"));
57852a38012Sejakowatz}
579410d5c37SAxel Dörfler
580410d5c37SAxel Dörfler
581410d5c37SAxel Dörflerbool
582410d5c37SAxel DörflerBLooper::IsLocked() const
58352a38012Sejakowatz{
584c01f349eSAxel Dörfler	if (!gLooperList.IsLooperValid(this)) {
58552a38012Sejakowatz		// The looper is gone, so of course it's not locked
58652a38012Sejakowatz		return false;
58752a38012Sejakowatz	}
58852a38012Sejakowatz
589616e68e7SAxel Dörfler	uint32 stack;
5909be774b5SAlex Smith	return ((addr_t)&stack & ~(B_PAGE_SIZE - 1)) == fCachedStack
591616e68e7SAxel Dörfler		|| find_thread(NULL) == fOwner;
59252a38012Sejakowatz}
593410d5c37SAxel Dörfler
594410d5c37SAxel Dörfler
595410d5c37SAxel Dörflerstatus_t
596410d5c37SAxel DörflerBLooper::LockWithTimeout(bigtime_t timeout)
59752a38012Sejakowatz{
59876858a33SIngo Weinhold	return _Lock(this, -1, timeout);
59952a38012Sejakowatz}
600410d5c37SAxel Dörfler
601410d5c37SAxel Dörfler
602410d5c37SAxel Dörflerthread_id
603410d5c37SAxel DörflerBLooper::Thread() const
60452a38012Sejakowatz{
605c01f349eSAxel Dörfler	return fThread;
60652a38012Sejakowatz}
607410d5c37SAxel Dörfler
608410d5c37SAxel Dörfler
609410d5c37SAxel Dörflerteam_id
610410d5c37SAxel DörflerBLooper::Team() const
61152a38012Sejakowatz{
612c01f349eSAxel Dörfler	return BPrivate::current_team();
61352a38012Sejakowatz}
614410d5c37SAxel Dörfler
615410d5c37SAxel Dörfler
616410d5c37SAxel DörflerBLooper*
617c01f349eSAxel DörflerBLooper::LooperForThread(thread_id thread)
61852a38012Sejakowatz{
619c01f349eSAxel Dörfler	return gLooperList.LooperForThread(thread);
62052a38012Sejakowatz}
621410d5c37SAxel Dörfler
622410d5c37SAxel Dörfler
623410d5c37SAxel Dörflerthread_id
624410d5c37SAxel DörflerBLooper::LockingThread() const
62552a38012Sejakowatz{
62652a38012Sejakowatz	return fOwner;
62752a38012Sejakowatz}
628410d5c37SAxel Dörfler
629410d5c37SAxel Dörfler
630410d5c37SAxel Dörflerint32
631410d5c37SAxel DörflerBLooper::CountLocks() const
63252a38012Sejakowatz{
63352a38012Sejakowatz	return fOwnerCount;
63452a38012Sejakowatz}
635410d5c37SAxel Dörfler
636410d5c37SAxel Dörfler
637410d5c37SAxel Dörflerint32
638410d5c37SAxel DörflerBLooper::CountLockRequests() const
63952a38012Sejakowatz{
64052a38012Sejakowatz	return fAtomicCount;
64152a38012Sejakowatz}
642410d5c37SAxel Dörfler
643410d5c37SAxel Dörfler
644410d5c37SAxel Dörflersem_id
645410d5c37SAxel DörflerBLooper::Sem() const
64652a38012Sejakowatz{
64752a38012Sejakowatz	return fLockSem;
64852a38012Sejakowatz}
649410d5c37SAxel Dörfler
650410d5c37SAxel Dörfler
651410d5c37SAxel DörflerBHandler*
652be902ac4SJohn ScipioneBLooper::ResolveSpecifier(BMessage* message, int32 index, BMessage* specifier,
653be902ac4SJohn Scipione	int32 what, const char* property)
65452a38012Sejakowatz{
6552284462cSejakowatz/**
6562284462cSejakowatz	@note	When I was first dumping the results of GetSupportedSuites() from
6572284462cSejakowatz			various classes, the use of the extra_data field was quite
6582284462cSejakowatz			mysterious to me.  Then I dumped BApplication and compared the
6592284462cSejakowatz			result against the BeBook's docs for scripting BApplication.  A
6602284462cSejakowatz			bunch of it isn't documented, but what is tipped me to the idea
6612284462cSejakowatz			that the extra_data is being used as a quick and dirty way to tell
6622284462cSejakowatz			what scripting "command" has been sent, e.g., for easy use in a
6632284462cSejakowatz			switch statement.  Would certainly be a lot faster than a bunch of
6642284462cSejakowatz			string comparisons -- which wouldn't tell the whole story anyway,
6652284462cSejakowatz			because of the same name being used for multiple properties.
6662284462cSejakowatz */
667edbfa1c7SAxel Dörfler 	BPropertyInfo propertyInfo(sLooperPropInfo);
6682284462cSejakowatz	uint32 data;
669b07c31a7Sejakowatz	status_t err = B_OK;
670b07c31a7Sejakowatz	const char* errMsg = "";
671be902ac4SJohn Scipione	if (propertyInfo.FindMatch(message, index, specifier, what, property, &data)
6728417b8d8SAxel Dörfler			>= 0) {
673410d5c37SAxel Dörfler		switch (data) {
6742e2e159aSejakowatz			case BLOOPER_PROCESS_INTERNALLY:
6752e2e159aSejakowatz				return this;
6762e2e159aSejakowatz
6772e2e159aSejakowatz			case BLOOPER_HANDLER_BY_INDEX:
6782e2e159aSejakowatz			{
6792e2e159aSejakowatz				int32 index = specifier->FindInt32("index");
680be902ac4SJohn Scipione				if (what == B_REVERSE_INDEX_SPECIFIER) {
6812e2e159aSejakowatz					index = CountHandlers() - index;
6822e2e159aSejakowatz				}
6832e2e159aSejakowatz				BHandler* target = HandlerAt(index);
684410d5c37SAxel Dörfler				if (target) {
6852e2e159aSejakowatz					// Specifier has been fully handled
686be902ac4SJohn Scipione					message->PopSpecifier();
6872e2e159aSejakowatz					return target;
688410d5c37SAxel Dörfler				} else {
689b07c31a7Sejakowatz					err = B_BAD_INDEX;
690b07c31a7Sejakowatz					errMsg = "handler index out of range";
6912e2e159aSejakowatz				}
692b07c31a7Sejakowatz				break;
6932e2e159aSejakowatz			}
694b07c31a7Sejakowatz
695b07c31a7Sejakowatz			default:
696b07c31a7Sejakowatz				err = B_BAD_SCRIPT_SYNTAX;
697b07c31a7Sejakowatz				errMsg = "Didn't understand the specifier(s)";
6982e2e159aSejakowatz		}
699410d5c37SAxel Dörfler	} else {
700be902ac4SJohn Scipione		return BHandler::ResolveSpecifier(message, index, specifier, what,
701410d5c37SAxel Dörfler			property);
702ec9673bfSejakowatz	}
70352a38012Sejakowatz
704f4fc3d62SJérôme Duval	BMessage reply(B_MESSAGE_NOT_UNDERSTOOD);
705f4fc3d62SJérôme Duval	reply.AddInt32("error", err);
706f4fc3d62SJérôme Duval	reply.AddString("message", errMsg);
707be902ac4SJohn Scipione	message->SendReply(&reply);
70852a38012Sejakowatz
70952a38012Sejakowatz	return NULL;
71052a38012Sejakowatz}
711410d5c37SAxel Dörfler
712410d5c37SAxel Dörfler
713410d5c37SAxel Dörflerstatus_t
714410d5c37SAxel DörflerBLooper::GetSupportedSuites(BMessage* data)
71552a38012Sejakowatz{
716410d5c37SAxel Dörfler	if (data == NULL)
717410d5c37SAxel Dörfler		return B_BAD_VALUE;
718ec9673bfSejakowatz
719e91315aaSJérôme Duval	status_t status = data->AddString("suites", "suite/vnd.Be-looper");
720410d5c37SAxel Dörfler	if (status == B_OK) {
721edbfa1c7SAxel Dörfler		BPropertyInfo PropertyInfo(sLooperPropInfo);
722f4fc3d62SJérôme Duval		status = data->AddFlat("messages", &PropertyInfo);
723410d5c37SAxel Dörfler		if (status == B_OK)
724410d5c37SAxel Dörfler			status = BHandler::GetSupportedSuites(data);
725ec9673bfSejakowatz	}
726ec9673bfSejakowatz
727410d5c37SAxel Dörfler	return status;
72852a38012Sejakowatz}
729410d5c37SAxel Dörfler
730410d5c37SAxel Dörfler
731410d5c37SAxel Dörflervoid
732410d5c37SAxel DörflerBLooper::AddCommonFilter(BMessageFilter* filter)
73352a38012Sejakowatz{
734be902ac4SJohn Scipione	if (filter == NULL)
7357bf6c069Sejakowatz		return;
7367bf6c069Sejakowatz
737410d5c37SAxel Dörfler	AssertLocked();
7387bf6c069Sejakowatz
739410d5c37SAxel Dörfler	if (filter->Looper()) {
7400b55d664Sejakowatz		debugger("A MessageFilter can only be used once.");
741cb5b0f6dSejakowatz		return;
7420b55d664Sejakowatz	}
7430b55d664Sejakowatz
744be902ac4SJohn Scipione	if (fCommonFilters == NULL)
74552a38012Sejakowatz		fCommonFilters = new BList(FILTER_LIST_BLOCK_SIZE);
746410d5c37SAxel Dörfler
74752a38012Sejakowatz	filter->SetLooper(this);
74852a38012Sejakowatz	fCommonFilters->AddItem(filter);
74952a38012Sejakowatz}
750410d5c37SAxel Dörfler
751410d5c37SAxel Dörfler
752410d5c37SAxel Dörflerbool
753410d5c37SAxel DörflerBLooper::RemoveCommonFilter(BMessageFilter* filter)
75452a38012Sejakowatz{
755410d5c37SAxel Dörfler	AssertLocked();
7560b55d664Sejakowatz
757be902ac4SJohn Scipione	if (fCommonFilters == NULL)
7580b55d664Sejakowatz		return false;
7590b55d664Sejakowatz
76052a38012Sejakowatz	bool result = fCommonFilters->RemoveItem(filter);
76152a38012Sejakowatz	if (result)
76252a38012Sejakowatz		filter->SetLooper(NULL);
76352a38012Sejakowatz
76452a38012Sejakowatz	return result;
76552a38012Sejakowatz}
766410d5c37SAxel Dörfler
767410d5c37SAxel Dörfler
768410d5c37SAxel Dörflervoid
769410d5c37SAxel DörflerBLooper::SetCommonFilterList(BList* filters)
77052a38012Sejakowatz{
771410d5c37SAxel Dörfler	AssertLocked();
772ff1ade6bSejakowatz
773cb5b0f6dSejakowatz	BMessageFilter* filter;
774410d5c37SAxel Dörfler	if (filters) {
7758417b8d8SAxel Dörfler		// Check for ownership issues - a filter can only have one owner
776410d5c37SAxel Dörfler		for (int32 i = 0; i < filters->CountItems(); ++i) {
777cb5b0f6dSejakowatz			filter = (BMessageFilter*)filters->ItemAt(i);
778410d5c37SAxel Dörfler			if (filter->Looper()) {
779cb5b0f6dSejakowatz				debugger("A MessageFilter can only be used once.");
780cb5b0f6dSejakowatz				return;
781cb5b0f6dSejakowatz			}
782cb5b0f6dSejakowatz		}
783cb5b0f6dSejakowatz	}
784410d5c37SAxel Dörfler
785410d5c37SAxel Dörfler	if (fCommonFilters) {
786410d5c37SAxel Dörfler		for (int32 i = 0; i < fCommonFilters->CountItems(); ++i) {
78717e6de7aSshadow			delete (BMessageFilter*)fCommonFilters->ItemAt(i);
78852a38012Sejakowatz		}
789ff1ade6bSejakowatz
790ff1ade6bSejakowatz		delete fCommonFilters;
791ff1ade6bSejakowatz		fCommonFilters = NULL;
79252a38012Sejakowatz	}
79352a38012Sejakowatz
79452a38012Sejakowatz	// Per the BeBook, we take ownership of the list
79552a38012Sejakowatz	fCommonFilters = filters;
796410d5c37SAxel Dörfler	if (fCommonFilters) {
797410d5c37SAxel Dörfler		for (int32 i = 0; i < fCommonFilters->CountItems(); ++i) {
798cb5b0f6dSejakowatz			filter = (BMessageFilter*)fCommonFilters->ItemAt(i);
799cb5b0f6dSejakowatz			filter->SetLooper(this);
80052a38012Sejakowatz		}
80152a38012Sejakowatz	}
80252a38012Sejakowatz}
803410d5c37SAxel Dörfler
804410d5c37SAxel Dörfler
805410d5c37SAxel DörflerBList*
806410d5c37SAxel DörflerBLooper::CommonFilterList() const
80752a38012Sejakowatz{
80852a38012Sejakowatz	return fCommonFilters;
80952a38012Sejakowatz}
810410d5c37SAxel Dörfler
811410d5c37SAxel Dörfler
812410d5c37SAxel Dörflerstatus_t
813410d5c37SAxel DörflerBLooper::Perform(perform_code d, void* arg)
81452a38012Sejakowatz{
81552a38012Sejakowatz	// This is sort of what we're doing for this function everywhere
816cb5b0f6dSejakowatz	return BHandler::Perform(d, arg);
81752a38012Sejakowatz}
818410d5c37SAxel Dörfler
819410d5c37SAxel Dörfler
820410d5c37SAxel DörflerBMessage*
821410d5c37SAxel DörflerBLooper::MessageFromPort(bigtime_t timeout)
82252a38012Sejakowatz{
82352a38012Sejakowatz	return ReadMessageFromPort(timeout);
82452a38012Sejakowatz}
825410d5c37SAxel Dörfler
826410d5c37SAxel Dörfler
827410d5c37SAxel Dörflervoid BLooper::_ReservedLooper1() {}
828410d5c37SAxel Dörflervoid BLooper::_ReservedLooper2() {}
829410d5c37SAxel Dörflervoid BLooper::_ReservedLooper3() {}
830410d5c37SAxel Dörflervoid BLooper::_ReservedLooper4() {}
831410d5c37SAxel Dörflervoid BLooper::_ReservedLooper5() {}
832410d5c37SAxel Dörflervoid BLooper::_ReservedLooper6() {}
833410d5c37SAxel Dörfler
834410d5c37SAxel Dörfler
835ebb0db62SAugustin Cavalier#ifdef _BEOS_R5_COMPATIBLE_
8368417b8d8SAxel DörflerBLooper::BLooper(const BLooper& other)
83752a38012Sejakowatz{
83852a38012Sejakowatz	// Copy construction not allowed
83952a38012Sejakowatz}
840410d5c37SAxel Dörfler
841410d5c37SAxel Dörfler
8428417b8d8SAxel DörflerBLooper&
8438417b8d8SAxel DörflerBLooper::operator=(const BLooper& other)
84452a38012Sejakowatz{
84552a38012Sejakowatz	// Looper copying not allowed
846822cdddbSIngo Weinhold	return *this;
84752a38012Sejakowatz}
848ebb0db62SAugustin Cavalier#endif
849410d5c37SAxel Dörfler
850410d5c37SAxel Dörfler
85152a38012SejakowatzBLooper::BLooper(int32 priority, port_id port, const char* name)
85252a38012Sejakowatz{
8531480e5daSAxel Dörfler	_InitData(name, priority, port, B_LOOPER_PORT_DEFAULT_CAPACITY);
85452a38012Sejakowatz}
855683be71eSAxel Dörfler
856683be71eSAxel Dörfler
857683be71eSAxel Dörflerstatus_t
858fd5c87d5SAxel DörflerBLooper::_PostMessage(BMessage* msg, BHandler* handler, BHandler* replyTo)
85952a38012Sejakowatz{
860683be71eSAxel Dörfler	status_t status;
861683be71eSAxel Dörfler	BMessenger messenger(handler, this, &status);
862683be71eSAxel Dörfler	if (status == B_OK)
863fd5c87d5SAxel Dörfler		return messenger.SendMessage(msg, replyTo, 0);
86452a38012Sejakowatz
865683be71eSAxel Dörfler	return status;
866683be71eSAxel Dörfler}
86752a38012Sejakowatz
86852a38012Sejakowatz
869c01f349eSAxel Dörfler/*!
870c01f349eSAxel Dörfler	Locks a looper either by port or using a direct pointer to the looper.
871c01f349eSAxel Dörfler
872c01f349eSAxel Dörfler	\param looper looper to lock, if not NULL
873c01f349eSAxel Dörfler	\param port port to identify the looper in case \a looper is NULL
874c01f349eSAxel Dörfler	\param timeout timeout for acquiring the lock
875c01f349eSAxel Dörfler*/
876683be71eSAxel Dörflerstatus_t
877c01f349eSAxel DörflerBLooper::_Lock(BLooper* looper, port_id port, bigtime_t timeout)
87852a38012Sejakowatz{
879c01f349eSAxel Dörfler	PRINT(("BLooper::_Lock(%p, %lx)\n", looper, port));
88052a38012Sejakowatz
88152a38012Sejakowatz	//	Check params (loop, port)
882c01f349eSAxel Dörfler	if (looper == NULL && port < 0) {
883c01f349eSAxel Dörfler		PRINT(("BLooper::_Lock() done 1\n"));
88452a38012Sejakowatz		return B_BAD_VALUE;
88552a38012Sejakowatz	}
88652a38012Sejakowatz
887c01f349eSAxel Dörfler	thread_id currentThread = find_thread(NULL);
888c01f349eSAxel Dörfler	int32 oldCount;
88952a38012Sejakowatz	sem_id sem;
89052a38012Sejakowatz
89152a38012Sejakowatz	{
8922b2ec438SIngo Weinhold		AutoLocker<BLooperList> ListLock(gLooperList);
89352a38012Sejakowatz		if (!ListLock.IsLocked())
89452a38012Sejakowatz			return B_BAD_VALUE;
895c01f349eSAxel Dörfler
896