Skip to content

Commit

Permalink
[wip] avrt: Partly implement AvSetMmThreadCharacteristics().
Browse files Browse the repository at this point in the history
This is needed for native xaudio2 to gain real-time priorities.

Signed-off-by: Kai Krakow <[email protected]>
  • Loading branch information
kakra committed Jan 11, 2019
1 parent bb17a5b commit a29b655
Showing 1 changed file with 258 additions and 10 deletions.
268 changes: 258 additions & 10 deletions dlls/avrt/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,47 @@
#include "winbase.h"
#include "winnls.h"
#include "wine/debug.h"
#include "wine/heap.h"
#include "wine/list.h"
#include "wine/server.h"
#include "avrt.h"

#define AVRT_INVALID_HANDLE 0

enum avrt_task_type
{
AVRT_TASK_TYPE_NONE,
AVRT_TASK_TYPE_MMCSS,
};

enum avrt_scheduling_category
{
AVRT_SC_LOW,
AVRT_SC_MEDIUM,
AVRT_SC_HIGH,
};

typedef struct _AVRT_TASK
{
enum avrt_task_type type;
void *object;
struct list entry;
} AVRT_TASK, *PAVRT_TASK;

static struct list avrt_tasks = LIST_INIT(avrt_tasks);

typedef struct _AVRT_TASK_MMCSS
{
DWORD index;
DWORD affinity;
BOOL background_only;
BYTE background_priority;
DWORD clock_rate;
BYTE gpu_priority;
BYTE priority;
enum avrt_scheduling_category scheduling_category;
} AVRT_TASK_MMCSS, *PAVRT_TASK_MMCSS;

WINE_DEFAULT_DEBUG_CHANNEL(avrt);

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
Expand All @@ -45,6 +84,58 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
return TRUE;
}

/* Handle table functions */
static void *avrt_get_object(HANDLE handle, enum avrt_task_type type)
{
AVRT_TASK *task = handle;

if (handle == AVRT_INVALID_HANDLE)
{
WARN("Invalid handle %p passed.\n", handle);
return NULL;
}

if (task->type != type)
{
WARN("Handle %p is not of type %#x.\n", handle, type);
return NULL;
}

return task->object;
}

static HANDLE avrt_allocate_task(void *object, enum avrt_task_type type)
{
AVRT_TASK *task = heap_alloc_zero(sizeof(AVRT_TASK));

if (!task)
{
ERR("Failed to allocate handle table memory.\n");
SetLastError(ERROR_OUTOFMEMORY);
return AVRT_INVALID_HANDLE;
}

task->type = type;
task->object = object;
list_add_tail(&avrt_tasks, &task->entry);

return (HANDLE)task;
}

static void *avrt_free_task(HANDLE handle, enum avrt_task_type type)
{
AVRT_TASK *task = handle;
void *object = avrt_get_object(handle, type);

if (object)
{
list_remove(&task->entry);
heap_free(task);
}

return object;
}

HANDLE WINAPI AvSetMmThreadCharacteristicsA(LPCSTR TaskName, LPDWORD TaskIndex)
{
HANDLE ret;
Expand All @@ -66,21 +157,104 @@ HANDLE WINAPI AvSetMmThreadCharacteristicsA(LPCSTR TaskName, LPDWORD TaskIndex)
return ret;
}

HANDLE WINAPI AvSetMmThreadCharacteristicsW(LPCWSTR TaskName, LPDWORD TaskIndex)
/***********************************************************************
* AvSetMmThreadCharacteristicsW [AVRT.@]
*
* Creates a task instance with the specified scheduling characteristic.
*
* PARAMS
* task_name [I] A task name as defined in the system profile.
* task_index [O] An index identifying the thread group of this task.
*
* RETURNS
* Success: AVRT task handle.
* Failure: NULL.
*
* NOTES
* According to patent US7802256, the task index is an allocated index
* identifying the threading group of this task. This property should be
* inherited by child threads to identify all threads belonging to this
* specific task. Adjusting priorities later would affect all threads with
* the same task index then. For now, we just ignore this: This grouping is
* currently not embedded into wineserver. We will just create an index
* value and won't ever inherit it to child threads. If this is needed at
* some point, cgroups may be a proper way to group processes for the
* linux scheduler and also enable bandwidth reservations and guarantees.
*/
HANDLE WINAPI AvSetMmThreadCharacteristicsW(LPCWSTR task_name, LPDWORD task_index)
{
FIXME("(%s,%p): stub\n", debugstr_w(TaskName), TaskIndex);
AVRT_TASK_MMCSS *object = NULL;
AVRT_TASK *task = NULL;
DWORD index = GetCurrentThreadId();
HANDLE current_thread = GetCurrentThread();
BOOL existing_task = FALSE;
NTSTATUS ret;

if (!TaskName)
FIXME("(%s)->(%p)\n", debugstr_w(task_name), task_index);

if (!task_name)
{
SetLastError(ERROR_INVALID_TASK_NAME);
return NULL;
}
if (!TaskIndex)

if (!task_index)
{
SetLastError(ERROR_INVALID_HANDLE);
SetLastError(ERROR_INVALID_TASK_INDEX);
return NULL;
}
return (HANDLE)0x12345678;

if (*task_index != 0)
{
LIST_FOR_EACH_ENTRY(task, &avrt_tasks, AVRT_TASK, entry)
{
object = avrt_get_object(task, AVRT_TASK_TYPE_MMCSS);
if (object && (object->index == *task_index))
{
existing_task = TRUE;
goto setup_task;
}
}

SetLastError(ERROR_INVALID_TASK_INDEX);
return NULL;
}

object = heap_alloc_zero(sizeof(*object));
if (!object)
goto fail;

object->index = index;

task = avrt_allocate_task(object, AVRT_TASK_TYPE_MMCSS);
if (task != AVRT_INVALID_HANDLE)
goto setup_task;

fail:
if (!existing_task)
{
heap_free(task);
heap_free(object);
}
return NULL;

setup_task:
FIXME("not using MMCSS (TaskIndex=%d)\n", index);
SERVER_START_REQ(set_thread_mmcss_priority)
{
req->handle = wine_server_obj_handle(current_thread);
req->mmcss_priority = 23;
ret = wine_server_call(req);
}
SERVER_END_REQ;

if (ret)
{
SetLastError(ret);
goto fail;
}

return task;
}

BOOL WINAPI AvQuerySystemResponsiveness(HANDLE AvrtHandle, ULONG *value)
Expand All @@ -89,14 +263,88 @@ BOOL WINAPI AvQuerySystemResponsiveness(HANDLE AvrtHandle, ULONG *value)
return FALSE;
}

BOOL WINAPI AvRevertMmThreadCharacteristics(HANDLE AvrtHandle)
BOOL WINAPI AvRevertMmThreadCharacteristics(HANDLE handle)
{
FIXME("(%p): stub\n", AvrtHandle);
DWORD index = GetCurrentThreadId();
HANDLE current_thread = GetCurrentThread();
AVRT_TASK_MMCSS *object;
NTSTATUS ret;

TRACE("(%p)\n", handle);

object = avrt_free_task(handle, AVRT_TASK_TYPE_MMCSS);

if (!object)
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}

if (object->index != index)
{
SetLastError(ERROR_INVALID_TASK_INDEX);
return FALSE;
}

FIXME("not using MMCSS\n");
SERVER_START_REQ(set_thread_mmcss_priority)
{
req->handle = wine_server_obj_handle(current_thread);
req->mmcss_priority = 0;
ret = wine_server_call(req);
}
SERVER_END_REQ;

if (ret)
{
SetLastError(ret);
return FALSE;
}

heap_free(object);
return TRUE;
}

BOOL WINAPI AvSetMmThreadPriority(HANDLE AvrtHandle, AVRT_PRIORITY prio)
BOOL WINAPI AvSetMmThreadPriority(HANDLE handle, AVRT_PRIORITY prio)
{
FIXME("(%p)->(%u) stub\n", AvrtHandle, prio);
FIXME("(%p, %u)\n", handle, prio);

#if 0
AVRT_TASK_MMCSS *object;

object = avrt_get_object(handle, AVRT_TASK_TYPE_MMCSS);

switch (prio)
{
case AVRT_PRIORITY_LOW:
{
prio = THREAD_PRIORITY_LOWEST;
break;
}
case AVRT_PRIORITY_NORMAL:
{
prio = THREAD_PRIORITY_NORMAL;
break;
}
case AVRT_PRIORITY_HIGH:
{
prio = THREAD_PRIORITY_HIGHEST;
break;
}
case AVRT_PRIORITY_CRITICAL:
{
prio = THREAD_PRIORITY_TIME_CRITICAL;
break;
}
default:
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
}

return SetThreadPriority(entry->thread, prio);
#else
return TRUE;
#endif
}

0 comments on commit a29b655

Please sign in to comment.