audioutilsprivate: restore thread priority before ending

The priority of the thread that executes audioringbuffer_thread_func
is incremented on Windows by the usage of the AvSetMmThreadCharacteristics
API. This change has to be restored, as described on the documentation
of the API (https://docs.microsoft.com/en-us/windows/win32/api/avrt/nf-avrt-avsetmmthreadcharacteristicsw#remarks),
with a call to the AvRevertMmThreadCharacteristics. If this is not done,
a handle will be leaked.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-base/-/merge_requests/760>
This commit is contained in:
Silvio Lazzeretti 2020-07-16 14:34:51 +02:00
parent f0a9907097
commit aa4bea913b
4 changed files with 53 additions and 8 deletions

View file

@ -205,6 +205,7 @@ audioringbuffer_thread_func (GstAudioRingBuffer * buf)
WriteFunc writefunc; WriteFunc writefunc;
GstMessage *message; GstMessage *message;
GValue val = { 0 }; GValue val = { 0 };
gpointer handle;
sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf)); sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
csink = GST_AUDIO_SINK_GET_CLASS (sink); csink = GST_AUDIO_SINK_GET_CLASS (sink);
@ -220,7 +221,7 @@ audioringbuffer_thread_func (GstAudioRingBuffer * buf)
if (writefunc == NULL) if (writefunc == NULL)
goto no_function; goto no_function;
if (G_UNLIKELY (!__gst_audio_set_thread_priority ())) if (G_UNLIKELY (!__gst_audio_set_thread_priority (&handle)))
GST_WARNING_OBJECT (sink, "failed to set thread priority"); GST_WARNING_OBJECT (sink, "failed to set thread priority");
message = gst_message_new_stream_status (GST_OBJECT_CAST (buf), message = gst_message_new_stream_status (GST_OBJECT_CAST (buf),
@ -306,6 +307,9 @@ stop_running:
g_value_unset (&val); g_value_unset (&val);
GST_DEBUG_OBJECT (sink, "posting LEAVE stream status"); GST_DEBUG_OBJECT (sink, "posting LEAVE stream status");
gst_element_post_message (GST_ELEMENT_CAST (sink), message); gst_element_post_message (GST_ELEMENT_CAST (sink), message);
if (G_UNLIKELY (!__gst_audio_restore_thread_priority (handle)))
GST_WARNING_OBJECT (sink, "failed to restore thread priority");
return; return;
} }
} }

View file

@ -187,6 +187,7 @@ audioringbuffer_thread_func (GstAudioRingBuffer * buf)
ReadFunc readfunc; ReadFunc readfunc;
GstMessage *message; GstMessage *message;
GValue val = { 0 }; GValue val = { 0 };
gpointer handle;
src = GST_AUDIO_SRC (GST_OBJECT_PARENT (buf)); src = GST_AUDIO_SRC (GST_OBJECT_PARENT (buf));
csrc = GST_AUDIO_SRC_GET_CLASS (src); csrc = GST_AUDIO_SRC_GET_CLASS (src);
@ -196,7 +197,7 @@ audioringbuffer_thread_func (GstAudioRingBuffer * buf)
if ((readfunc = csrc->read) == NULL) if ((readfunc = csrc->read) == NULL)
goto no_function; goto no_function;
if (G_UNLIKELY (!__gst_audio_set_thread_priority ())) if (G_UNLIKELY (!__gst_audio_set_thread_priority (&handle)))
GST_WARNING_OBJECT (src, "failed to set thread priority"); GST_WARNING_OBJECT (src, "failed to set thread priority");
message = gst_message_new_stream_status (GST_OBJECT_CAST (buf), message = gst_message_new_stream_status (GST_OBJECT_CAST (buf),
@ -281,6 +282,9 @@ stop_running:
g_value_unset (&val); g_value_unset (&val);
GST_DEBUG_OBJECT (src, "posting LEAVE stream status"); GST_DEBUG_OBJECT (src, "posting LEAVE stream status");
gst_element_post_message (GST_ELEMENT_CAST (src), message); gst_element_post_message (GST_ELEMENT_CAST (src), message);
if (G_UNLIKELY (!__gst_audio_restore_thread_priority (handle)))
GST_WARNING_OBJECT (src, "failed to restore thread priority");
return; return;
} }
} }

View file

@ -281,20 +281,54 @@ __gst_audio_init_thread_priority (void)
* Increases the priority of the thread it's called from * Increases the priority of the thread it's called from
*/ */
gboolean gboolean
__gst_audio_set_thread_priority (void) __gst_audio_set_thread_priority (gpointer * handle)
{ {
#ifdef G_OS_WIN32 #ifdef G_OS_WIN32
DWORD taskIndex = 0; DWORD taskIndex = 0;
#endif #endif
g_return_val_if_fail (handle != NULL, FALSE);
*handle = NULL;
if (!__gst_audio_init_thread_priority ()) if (!__gst_audio_init_thread_priority ())
return FALSE; return FALSE;
#ifdef G_OS_WIN32 #ifdef G_OS_WIN32
/* This is only used from ringbuffer thread functions, so we don't need to /* This is only used from ringbuffer thread functions */
* ever need to revert the thread priorities. */ *handle = (gpointer)
return _gst_audio_avrt_tbl.AvSetMmThreadCharacteristics (TEXT ("Pro Audio"), _gst_audio_avrt_tbl.AvSetMmThreadCharacteristics (TEXT ("Pro Audio"),
&taskIndex) != 0; &taskIndex);
if (*handle == 0) {
gchar *errorMsg = g_win32_error_message (GetLastError ());
GST_WARNING
("Failed to set thread priority, AvSetMmThreadCharacteristics returned: %s",
errorMsg);
g_free (errorMsg);
}
return *handle != 0;
#else
return TRUE;
#endif
}
/*
* Restores the priority of the thread that was increased
* with __gst_audio_set_thread_priority.
* This function must be called from the same thread that called the
* __gst_audio_set_thread_priority function.
* See https://docs.microsoft.com/en-us/windows/win32/api/avrt/nf-avrt-avsetmmthreadcharacteristicsw#remarks
*/
gboolean
__gst_audio_restore_thread_priority (gpointer handle)
{
#ifdef G_OS_WIN32
if (!handle)
return FALSE;
return _gst_audio_avrt_tbl.AvRevertMmThreadCharacteristics ((HANDLE) handle);
#else #else
return TRUE; return TRUE;
#endif #endif

View file

@ -43,7 +43,10 @@ gboolean __gst_audio_encoded_audio_convert (GstAudioInfo * fmt, gint64 bytes,
gint64 * dest_value); gint64 * dest_value);
G_GNUC_INTERNAL G_GNUC_INTERNAL
gboolean __gst_audio_set_thread_priority (void); gboolean __gst_audio_set_thread_priority (gpointer * handle);
G_GNUC_INTERNAL
gboolean __gst_audio_restore_thread_priority (gpointer handle);
G_END_DECLS G_END_DECLS