Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SoundSource Plugin API: Version 8 #578

Merged
merged 52 commits into from
Jun 5, 2015
Merged

SoundSource Plugin API: Version 8 #578

merged 52 commits into from
Jun 5, 2015

Conversation

uklotzde
Copy link
Contributor

@uklotzde uklotzde commented May 7, 2015

Fixes https://bugs.launchpad.net/mixxx/+bug/1452651

File names for SoundSource plugins were truncated at the first occurrence of '#' due to an implicit conversion from QString to QUrl.

@uklotzde
Copy link
Contributor Author

I've bumped the SoundSource plugin API version from 7 to 8, re-defined the public library functions, and did some cleanup.

@uklotzde uklotzde changed the title SoundSource Plugins: Fix invalid truncation of file names SoundSource Plugin API: Version 8 May 14, 2015
@uklotzde
Copy link
Contributor Author

What has begun as a simple bug fix is now a refactoring of the SoundSource plugin framework ;)

inline QString getLocalFileName() const {
DEBUG_ASSERT(isLocalFile());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens on windows with network shares?
There is a pending bug for SMB locations
https://bugs.launchpad.net/mixxx/+bug/918222
Will this fail here?

@uklotzde
Copy link
Contributor Author

uklotzde commented Jun 4, 2015

@daschuer: I've reset the branch to the previous state without the priority extension. Adding the priority later will require to bump the plugin version from 8 to 9, but this is ok. We will not run out of version numbers soon ;)

The priority is only a "hint" to provide a reasonable default behavior without requiring any extra configuration by the user or some sort of GUI.

if (trackLocation.isEmpty()) {
return QImage();
}
DEBUG_ASSERT(!trackLocation.isEmpty());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally we should prefer DEBUG_ASSERT_AND_HANDLE.

DEBUG_ASSERT_AND_HANDLE(...) {
  return QImage();
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Empty file names and non-existent files are handled gracefully by SoundSourceProxy, we don't need to handle these errors here again. Instead of handling it twice I would prefer to remove the DEBUG_ASSERT entirely.

Empty file names are handled gracefully by SoundSourceProxy.

#include "sources/soundsource.h"

#include <QStringList>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing include for QUrl, QSharedPointer, QString

@rryan
Copy link
Member

rryan commented Jun 4, 2015

Thanks @uklotzde !

When Albert and I worked on the original plugin API we took care not to pass heap allocated objects across the DLL / binary boundary and free them on the other side. On Windows, this will cause immediate segfaults if the DLL and the binary are linked to different runtimes. You can see an example of this style with the old supportedFileExtensions/freeFileExtensions methods.

I notice that the 1.12 branch (pre-SS-refactor) commits a huge sin here by allocating the heap-allocated SoundSource itself in the plugin and freeing it in Mixxx so I think we've gotten sloppy over the years in this regard.

I'm worried about the use of QSharedPointer/QStrings in this version of the API. When the DLL allocates a QSharedPointer/QString and passes it to the main Mixxx binary, I believe the code executing to handle that object is the Mixxx binary's copy of QString/QSharedPointer code. Correct me if I'm wrong!

So when the QSharedPointer destructor runs, the Mixxx binary QSharedPointer destructor is what is actually running, which will free the SoundSourceProvider using the Mixxx heap, not the DLL heap.

Have you given this any thought?

@uklotzde
Copy link
Contributor Author

uklotzde commented Jun 4, 2015

@rryan
Well, I know that special care has to be taken with DLLs and memory allocation. But my development experience on Windows lies more than 10 years behind in the past ;)

As you mentioned I've seen that many resources are allocated on one side and freed on the other: The SoundSource itself, QString with metadata, QImage with cover art, .... Only doing it right for the file extensions didn't seem to make any sense to me?! So I assumed that this doesn't matter here.

@uklotzde
Copy link
Contributor Author

uklotzde commented Jun 4, 2015

The C++ operators new and delete are now called symmetrically from within the external plugin libraries and should use the same C/C++ runtime. Unfortunately I'm not able to test if this works as expected for Windows DLLs.

@uklotzde
Copy link
Contributor Author

uklotzde commented Jun 5, 2015

@rryan
All invocations of operator new are now complemented by the corresponding invocation of operator delete within the same DLL. Allocations within Qt shouldn't matter here if Qt is doing it correctly in their DLL.


// Singleton: SoundSourceProviderM4A is stateless
// and a single instance can safely be shared
Mixxx::SoundSourceProviderM4A SOUNDSOURCE_PROVIDER;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

static variables should be camel case and prefixed with s

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general, we should avoid static variables in libraries.
Can't we make it a static local of Mixxx_SoundSourcePluginAPI_getSoundSourceProvider

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@daschuer Ok, using a static local variable is a viable option

@daschuer
Copy link
Member

daschuer commented Jun 5, 2015

Allocations within Qt shouldn't matter here if Qt is doing it correctly in their DLL.

I want to try to understand the issue. Here some thoughts, please correct me If I am wrong.

I wonder how Qt can do this with implicit sharing lets say in QString.
I think this will be linked by the Application and by the DLL to the QT DLL with their matching, but different memory model, finally to different implementations to malloc.
If now a QString is transfered from the APP to the dll, the QString content is allocated in the senders
heap model but might be deleted in the receivers model -> crash!

Is that correct?

If yes, We can use Qt containers only, if the linked used QT dlls are compiled with the same memory model. This means we cannot switch the memory model if we (only hypothetically) split out the plug-in builds. Since we can't do this anyway, we do not need to worry about a different memory models.

So we have finally no issues here, Right?

@uklotzde
Copy link
Contributor Author

uklotzde commented Jun 5, 2015

@daschuer Both app and plugin must be linked against the same shared Qt DLL. Then alll internal invocations of operator new/delete in Qt classes use the same C++ runtime and match. What happens in this library stays in this library ;)

We only need to take care of managed pointers. They have to be fed with the appropriate deleter upon construction. This ensures that operator delete from the plugin is called instead of that from the app. This approach should work even when the plugins are compiled separately.

@daschuer
Copy link
Member

daschuer commented Jun 5, 2015

Thanks for clarifying!

@rryan
Copy link
Member

rryan commented Jun 5, 2015

I'm considering the case where some external party releases a soundsource plugin DLL. I had been assuming they were statically linking their own version of Qt -- but I guess that's prone to causing other problems anyway so we may require that they dynamically link to Qt.

If we accept that they have to dynamically link to Qt (so they are using our Qt DLLs once we load their DLL) -- then I agree the heap used for shared Qt objects will be the one we chose when we compiled Qt.

@rryan
Copy link
Member

rryan commented Jun 5, 2015

Thanks for the changes @uklotzde!

rryan added a commit that referenced this pull request Jun 5, 2015
@rryan rryan merged commit c4532a0 into mixxxdj:master Jun 5, 2015
@uklotzde uklotzde deleted the SoundSourcePluginUrlFileNameFix branch July 18, 2015 12:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants