2 * Copyright (c) 2002, 2003 Marcus Overhagen <Marcus@Overhagen.de>
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files or portions
6 * thereof (the "Software"), to deal in the Software without restriction,
7 * including without limitation the rights to use, copy, modify, merge,
8 * publish, distribute, sublicense, and/or sell copies of the Software,
9 * and to permit persons to whom the Software is furnished to do so, subject
10 * to the following conditions:
12 * * Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
15 * * Redistributions in binary form must reproduce the above copyright notice
16 * in the binary, as well as this list of conditions and the following
17 * disclaimer in the documentation and/or other materials provided with
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
31 /*! This is a management class for dormant media nodes.
32 It is private to the media kit and only accessed by the BMediaRoster class
33 and the media_addon_server.
34 It handles loading/unloading of dormant nodes.
36 Dormant media nodes can be instantiated on demand. The reside on harddisk in
37 the directories /boot/beos/system/add-ons/media
38 and /boot/home/config/add-ons/media.
39 Multiple media nodes can be included in one file, they can be accessed using
40 the BMediaAddOn that each file implements.
41 The BMediaAddOn allows getting a list of supported flavors. Each flavor
42 represents a media node.
43 The media_addon_server does the initial scanning of files and getting the
44 list of supported flavors. It uses the flavor_info to do this, and reports
45 the list of flavors to the media_server packed into individual
46 dormant_media_node structures.
50 #include "DormantNodeManager.h"
60 #include <MediaMisc.h>
61 #include <ServerInterface.h>
62 #include <DataExchange.h>
69 DormantNodeManager
* gDormantNodeManager
;
70 // initialized by BMediaRoster.
73 DormantNodeManager::DormantNodeManager()
75 fLock("dormant node manager locker")
80 DormantNodeManager::~DormantNodeManager()
82 // force unloading all currently loaded images
84 AddOnMap::iterator iterator
= fAddOnMap
.begin();
85 for (; iterator
!= fAddOnMap
.end(); iterator
++) {
86 loaded_add_on_info
& info
= iterator
->second
;
88 ERROR("Forcing unload of add-on id %" B_PRId32
" with usecount %"
89 B_PRId32
"\n", info
.add_on
->AddonID(), info
.use_count
);
90 _UnloadAddOn(info
.add_on
, info
.image
);
96 DormantNodeManager::GetAddOn(media_addon_id id
)
98 TRACE("DormantNodeManager::GetAddon, id %" B_PRId32
"\n", id
);
100 // first try to use a already loaded add-on
101 BMediaAddOn
* addOn
= _LookupAddOn(id
);
105 // Be careful, we avoid locking here!
107 // ok, it's not loaded, try to get the path
109 if (FindAddOnPath(&path
, id
) != B_OK
) {
110 ERROR("DormantNodeManager::GetAddon: can't find path for add-on %"
116 BMediaAddOn
* newAddOn
;
118 if (_LoadAddOn(path
.Path(), id
, &newAddOn
, &image
) != B_OK
) {
119 ERROR("DormantNodeManager::GetAddon: can't load add-on %" B_PRId32
120 " from path %s\n",id
, path
.Path());
124 // ok, we successfully loaded it. Now lock and insert it into the map,
125 // or unload it if the map already contains one that was loaded by another
126 // thread at the same time
130 addOn
= _LookupAddOn(id
);
132 // we use the loaded one
135 // and save it into the list
136 loaded_add_on_info info
;
137 info
.add_on
= newAddOn
;
141 fAddOnMap
.insert(std::make_pair(id
, info
));
142 } catch (std::bad_alloc
& exception
) {
143 _UnloadAddOn(newAddOn
, image
);
147 _UnloadAddOn(newAddOn
, image
);
149 ASSERT(addOn
->AddonID() == id
);
155 DormantNodeManager::PutAddOn(media_addon_id id
)
157 TRACE("DormantNodeManager::PutAddon, id %" B_PRId32
"\n", id
);
159 BAutolock
locker(fLock
);
161 AddOnMap::iterator found
= fAddOnMap
.find(id
);
162 if (found
== fAddOnMap
.end()) {
163 ERROR("DormantNodeManager::PutAddon: failed to find add-on %" B_PRId32
168 loaded_add_on_info
& info
= found
->second
;
170 if (--info
.use_count
== 0) {
173 BMediaAddOn
* addOn
= info
.add_on
;
174 image_id image
= info
.image
;
175 fAddOnMap
.erase(found
);
178 _UnloadAddOn(addOn
, image
);
184 DormantNodeManager::PutAddOnDelayed(media_addon_id id
)
186 // Called from a node destructor of the loaded media-add-on.
187 // We must make sure that the media-add-on stays in memory
188 // a couple of seconds longer.
194 //! For use by media_addon_server only
196 DormantNodeManager::RegisterAddOn(const char* path
)
198 TRACE("DormantNodeManager::RegisterAddon, path %s\n", path
);
201 status_t status
= get_ref_for_path(path
, &ref
);
202 if (status
!= B_OK
) {
203 ERROR("DormantNodeManager::RegisterAddon failed, couldn't get ref "
204 "for path %s: %s\n", path
, strerror(status
));
208 server_register_add_on_request request
;
211 server_register_add_on_reply reply
;
212 status
= QueryServer(SERVER_REGISTER_ADD_ON
, &request
, sizeof(request
),
213 &reply
, sizeof(reply
));
214 if (status
!= B_OK
) {
215 ERROR("DormantNodeManager::RegisterAddon failed, couldn't talk to "
221 ERROR("DormantNodeManager::RegisterAddon failed, couldn't talk to "
222 "media server: %s\n", strerror(status
));
226 TRACE("DormantNodeManager::RegisterAddon finished with id %" B_PRId32
"\n",
229 return reply
.add_on_id
;
233 //! For use by media_addon_server only
235 DormantNodeManager::UnregisterAddOn(media_addon_id id
)
237 TRACE("DormantNodeManager::UnregisterAddon id %" B_PRId32
"\n", id
);
240 port_id port
= find_port(MEDIA_SERVER_PORT_NAME
);
244 server_unregister_add_on_command msg
;
246 write_port(port
, SERVER_UNREGISTER_ADD_ON
, &msg
, sizeof(msg
));
251 DormantNodeManager::FindAddOnPath(BPath
* path
, media_addon_id id
)
253 server_get_add_on_ref_request request
;
254 request
.add_on_id
= id
;
256 server_get_add_on_ref_reply reply
;
257 status_t status
= QueryServer(SERVER_GET_ADD_ON_REF
, &request
,
258 sizeof(request
), &reply
, sizeof(reply
));
262 entry_ref ref
= reply
.ref
;
263 return path
->SetTo(&ref
);
268 DormantNodeManager::_LookupAddOn(media_addon_id id
)
272 AddOnMap::iterator found
= fAddOnMap
.find(id
);
273 if (found
== fAddOnMap
.end())
276 loaded_add_on_info
& info
= found
->second
;
278 ASSERT(id
== info
.add_on
->AddonID());
286 DormantNodeManager::_LoadAddOn(const char* path
, media_addon_id id
,
287 BMediaAddOn
** _newAddOn
, image_id
* _newImage
)
289 image_id image
= load_add_on(path
);
291 ERROR("DormantNodeManager::LoadAddon: loading \"%s\" failed: %s\n",
292 path
, strerror(image
));
296 BMediaAddOn
* (*makeAddOn
)(image_id
);
297 status_t status
= get_image_symbol(image
, "make_media_addon",
298 B_SYMBOL_TYPE_TEXT
, (void**)&makeAddOn
);
299 if (status
!= B_OK
) {
300 ERROR("DormantNodeManager::LoadAddon: loading failed, function not "
301 "found: %s\n", strerror(status
));
302 unload_add_on(image
);
306 BMediaAddOn
* addOn
= makeAddOn(image
);
308 ERROR("DormantNodeManager::LoadAddon: creating BMediaAddOn failed\n");
309 unload_add_on(image
);
313 ASSERT(addOn
->ImageID() == image
);
314 // this should be true for a well behaving add-ons
316 // We are a friend class of BMediaAddOn and initialize these member
319 addOn
->fImage
= image
;
330 DormantNodeManager::_UnloadAddOn(BMediaAddOn
* addOn
, image_id image
)
332 ASSERT(addOn
!= NULL
);
333 ASSERT(addOn
->ImageID() == image
);
334 // if this fails, something bad happened to the add-on
337 unload_add_on(image
);
342 } // namespace BPrivate