2 * Copyright 2015, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
11 #include <NodeMonitor.h>
12 #include <VolumeRoster.h>
15 static BLooper
* sQueryLooper
= NULL
;
16 static pthread_once_t sInitOnce
= PTHREAD_ONCE_INIT
;
22 sQueryLooper
= new BLooper("query looper");
27 // #pragma mark - QueryListener
30 QueryListener::~QueryListener()
35 // #pragma mark - QueryList
38 QueryList::QueryList()
46 QueryList::~QueryList()
50 ThreadVector::const_iterator threadIterator
= fFetchThreads
.begin();
51 for (; threadIterator
!= fFetchThreads
.end(); threadIterator
++) {
52 wait_for_thread(*threadIterator
, NULL
);
55 QueryVector::iterator queryIterator
= fQueries
.begin();
56 for (; queryIterator
!= fQueries
.end(); queryIterator
++) {
57 delete *queryIterator
;
63 QueryList::Init(const char* predicate
, BVolume
* specificVolume
)
65 if (sQueryLooper
== NULL
)
66 pthread_once(&sInitOnce
, &initQueryLooper
);
69 debugger("Init() called twice!");
72 sQueryLooper
->AddHandler(this);
73 sQueryLooper
->Unlock();
75 if (specificVolume
== NULL
) {
79 while (roster
.GetNextVolume(&volume
) == B_OK
) {
80 if (volume
.KnowsQuery() && volume
.KnowsAttr() && volume
.KnowsMime())
81 _AddVolume(volume
, predicate
);
84 _AddVolume(*specificVolume
, predicate
);
91 QueryList::AddListener(QueryListener
* listener
)
93 BAutolock
locker(this);
95 // Add all entries that were already retrieved
96 RefMap::const_iterator iterator
= fRefs
.begin();
97 for (; iterator
!= fRefs
.end(); iterator
++) {
98 listener
->EntryCreated(*this, iterator
->second
, iterator
->first
.node
);
101 fListeners
.AddItem(listener
);
106 QueryList::RemoveListener(QueryListener
* listener
)
108 BAutolock
locker(this);
109 fListeners
.RemoveItem(listener
, false);
114 QueryList::MessageReceived(BMessage
* message
)
116 switch (message
->what
) {
119 int32 opcode
= message
->GetInt32("opcode", -1);
120 int64 directory
= message
->GetInt64("directory", -1);
121 int32 device
= message
->GetInt32("device", -1);
122 int64 node
= message
->GetInt64("node", -1);
124 if (opcode
== B_ENTRY_CREATED
) {
125 const char* name
= message
->GetString("name");
127 entry_ref
ref(device
, directory
, name
);
128 _AddEntry(ref
, node
);
130 } else if (opcode
== B_ENTRY_REMOVED
) {
131 node_ref
nodeRef(device
, node
);
132 _RemoveEntry(nodeRef
);
138 BHandler::MessageReceived(message
);
145 QueryList::_AddEntry(const entry_ref
& ref
, ino_t node
)
147 BAutolock
locker(this);
149 // TODO: catch bad_alloc
150 fRefs
.insert(std::make_pair(node_ref(ref
.device
, node
), ref
));
152 _NotifyEntryCreated(ref
, node
);
157 QueryList::_RemoveEntry(const node_ref
& nodeRef
)
159 BAutolock
locker(this);
160 RefMap::iterator found
= fRefs
.find(nodeRef
);
161 if (found
!= fRefs
.end())
162 _NotifyEntryRemoved(nodeRef
);
167 QueryList::_NotifyEntryCreated(const entry_ref
& ref
, ino_t node
)
171 int32 count
= fListeners
.CountItems();
172 for (int32 index
= 0; index
< count
; index
++) {
173 fListeners
.ItemAt(index
)->EntryCreated(*this, ref
, node
);
179 QueryList::_NotifyEntryRemoved(const node_ref
& nodeRef
)
183 int32 count
= fListeners
.CountItems();
184 for (int32 index
= 0; index
< count
; index
++) {
185 fListeners
.ItemAt(index
)->EntryRemoved(*this, nodeRef
);
191 QueryList::_AddVolume(BVolume
& volume
, const char* predicate
)
193 BQuery
* query
= new BQuery();
194 if (query
->SetVolume(&volume
) != B_OK
195 || query
->SetPredicate(predicate
) != B_OK
196 || query
->SetTarget(this) != B_OK
) {
200 // TODO: catch bad_alloc
201 fQueries
.push_back(query
);
203 fQueryQueue
.push_back(query
);
206 thread_id thread
= spawn_thread(_FetchQuery
, "query fetcher",
207 B_NORMAL_PRIORITY
, this);
208 if (thread
>= B_OK
) {
209 resume_thread(thread
);
211 fFetchThreads
.push_back(thread
);
217 QueryList::_FetchQuery(void* self
)
219 return static_cast<QueryList
*>(self
)->_FetchQuery();
224 QueryList::_FetchQuery()
228 BAutolock
locker(this);
229 BQuery
* query
= fQueryQueue
.back();
230 fQueryQueue
.pop_back();
236 while (!fQuit
&& query
->GetNextRef(&ref
) == B_OK
) {
239 if (entry
.GetNodeRef(&nodeRef
) == B_OK
)
240 map
.insert(std::make_pair(nodeRef
, ref
));
243 return B_INTERRUPTED
;
247 RefMap::const_iterator iterator
= map
.begin();
248 for (; iterator
!= map
.end(); iterator
++) {
249 _AddEntry(iterator
->second
, iterator
->first
.node
);