1// NodeHandleMap.cpp
2
3#include "NodeHandleMap.h"
4
5#include "AutoLocker.h"
6#include "GlobalBlockerPool.h"
7
8
9// constructor
10NodeHandleMap::NodeHandleMap(const char* name)
11	: Locker(name),
12	  fNextNodeHandleCookie(0)
13{
14}
15
16// destructor
17NodeHandleMap::~NodeHandleMap()
18{
19}
20
21// Init
22status_t
23NodeHandleMap::Init()
24{
25	// check semaphore
26	if (Sem() < 0)
27		return Sem();
28
29	return B_OK;
30}
31
32// AddNodeHandle
33status_t
34NodeHandleMap::AddNodeHandle(NodeHandle* handle)
35{
36	if (!handle)
37		return B_BAD_VALUE;
38
39	AutoLocker<Locker> _(this);
40
41	handle->SetCookie(_NextNodeHandleCookie());
42
43	status_t error = Put(handle->GetCookie(), handle);
44	if (error == B_OK)
45		handle->AcquireReference();
46
47	return error;
48}
49
50// RemoveNodeHandle
51bool
52NodeHandleMap::RemoveNodeHandle(NodeHandle* handle)
53{
54	if (!handle)
55		return false;
56
57	AutoLocker<Locker> _(this);
58
59	if (Get(handle->GetCookie()) != handle)
60		return false;
61
62	Remove(handle->GetCookie());
63	handle->ReleaseReference();
64	return true;
65}
66
67// LockNodeHandle
68//
69// VolumeManager must NOT be locked.
70status_t
71NodeHandleMap::LockNodeHandle(int32 cookie, NodeHandle** _handle)
72{
73	if (!_handle)
74		return B_BAD_VALUE;
75
76	NodeHandle* handle;
77	{
78		AutoLocker<Locker> _(this);
79
80		// get the node handle
81		handle = Get(cookie);
82		if (!handle)
83			return B_ENTRY_NOT_FOUND;
84		handle->AcquireReference();
85
86		// first attempt: we just try to lock the node handle, which will fail,
87		// if someone else has the lock at the momemt
88		if (handle->Lock()) {
89			*_handle = handle;
90			return B_OK;
91		}
92	}
93
94	// someone else is locking, get a blocker and wait for the lock
95	BlockerPool* blockerPool = GlobalBlockerPool::GetDefault();
96	Blocker blocker = blockerPool->GetBlocker();
97	BlockerPutter blockerPutter(*blockerPool, blocker);
98	LockerCandidate lockerCandidate(blocker);
99	{
100		AutoLocker<Locker> _(this);
101
102		if (handle->Lock()) {
103			*_handle = handle;
104			return B_OK;
105		}
106		handle->QueueLockerCandidate(&lockerCandidate);
107	}
108
109	// wait for the lock
110	status_t error = lockerCandidate.Block();
111	if (error != B_OK) {
112		handle->ReleaseReference();
113		return error;
114	}
115
116	*_handle = handle;
117	return B_OK;
118}
119
120// UnlockNodeHandle
121//
122// VolumeManager may or may not be locked.
123void
124NodeHandleMap::UnlockNodeHandle(NodeHandle* nodeHandle)
125{
126	if (!nodeHandle)
127		return;
128
129	if (nodeHandle->IsLocked()) {
130		AutoLocker<Locker> _(this);
131
132		nodeHandle->Unlock();
133		nodeHandle->ReleaseReference();
134	}
135}
136
137// _NextNodeHandleCookie
138int32
139NodeHandleMap::_NextNodeHandleCookie()
140{
141	int32 cookie;
142
143	do {
144		if (fNextNodeHandleCookie < 0)
145			fNextNodeHandleCookie = 0;
146		cookie = fNextNodeHandleCookie++;
147	} while (ContainsKey(cookie));
148
149	return cookie;
150}
151
152