clang on windows support

This commit is contained in:
wuggy 2026-09-10 08:32:59 -07:00
commit 1d44f05fba
22 changed files with 208 additions and 65 deletions

View file

@ -162,6 +162,13 @@ SOURCES += [
'xiph.c'
]
# dummy_funcs.c intentionally provides tentative definitions for FFmpeg
# objects that are disabled by the generated configuration. Clang's default
# -fno-common turns those placeholders into duplicate definitions when an
# enabled codec supplies the real object.
if CONFIG['CLANG_CL']:
SOURCES['dummy_funcs.c'].flags += ['-fcommon']
SYMBOLS_FILE = 'avcodec.symbols'
NO_VISIBILITY_FLAGS = True

View file

@ -41,7 +41,8 @@ static inline void atomic_int_set_win32(volatile int *ptr, int val)
#define avpriv_atomic_int_add_and_fetch atomic_int_add_and_fetch_win32
static inline int atomic_int_add_and_fetch_win32(volatile int *ptr, int inc)
{
return inc + InterlockedExchangeAdd(ptr, inc);
/* Windows int and LONG are both 32-bit, but have distinct C types. */
return inc + InterlockedExchangeAdd((volatile LONG *)ptr, inc);
}
#define avpriv_atomic_ptr_cas atomic_ptr_cas_win32

View file

@ -85,10 +85,24 @@ COLD int dav1d_num_logical_processors(Dav1dContext *const c) {
#ifdef _WIN32
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
GROUP_AFFINITY affinity;
if (GetThreadGroupAffinity(GetCurrentThread(), &affinity)) {
int num_processors = 1;
while (affinity.Mask &= affinity.Mask - 1)
DWORD_PTR mask = 0, system_mask;
HMODULE kernel32 = GetModuleHandleW(L"kernel32.dll");
typedef BOOL (WINAPI *get_thread_group_affinity_fn)(HANDLE, PGROUP_AFFINITY);
get_thread_group_affinity_fn get_thread_group_affinity = kernel32 ?
(get_thread_group_affinity_fn)GetProcAddress(kernel32, "GetThreadGroupAffinity") : NULL;
/* Processor groups are only available on Windows 7 and later. */
if (get_thread_group_affinity &&
get_thread_group_affinity(GetCurrentThread(), &affinity))
mask = affinity.Mask;
else if (!GetProcessAffinityMask(GetCurrentProcess(), &mask, &system_mask))
mask = 0;
if (mask) {
int num_processors = 0;
do {
num_processors++;
} while (mask &= mask - 1);
return num_processors;
}
#else

View file

@ -33,8 +33,8 @@
#include <limits.h>
#include <windows.h>
#define PTHREAD_MUTEX_INITIALIZER SRWLOCK_INIT
#define PTHREAD_ONCE_INIT INIT_ONCE_STATIC_INIT
#define PTHREAD_MUTEX_INITIALIZER { 0 }
#define PTHREAD_ONCE_INIT 0
typedef struct {
HANDLE h;
@ -46,9 +46,16 @@ typedef struct {
unsigned stack_size;
} pthread_attr_t;
typedef SRWLOCK pthread_mutex_t;
typedef CONDITION_VARIABLE pthread_cond_t;
typedef INIT_ONCE pthread_once_t;
typedef struct {
volatile LONG state;
CRITICAL_SECTION cs;
} pthread_mutex_t;
struct dav1d_cond_waiter;
typedef struct {
CRITICAL_SECTION cs;
struct dav1d_cond_waiter *head;
} pthread_cond_t;
typedef volatile LONG pthread_once_t;
void dav1d_init_thread(void);
void dav1d_set_thread_name(const wchar_t *name);
@ -84,50 +91,51 @@ static inline int pthread_attr_setstacksize(pthread_attr_t *const attr,
static inline int pthread_mutex_init(pthread_mutex_t *const mutex,
const void *const attr)
{
InitializeSRWLock(mutex);
mutex->state = 0;
return 0;
}
static inline int pthread_mutex_destroy(pthread_mutex_t *const mutex) {
if (mutex->state == 2) DeleteCriticalSection(&mutex->cs);
return 0;
}
static inline int pthread_mutex_lock(pthread_mutex_t *const mutex) {
AcquireSRWLockExclusive(mutex);
if (InterlockedCompareExchange(&mutex->state, 1, 0) == 0) {
InitializeCriticalSection(&mutex->cs);
InterlockedExchange(&mutex->state, 2);
} else {
while (InterlockedCompareExchange(&mutex->state, 2, 2) != 2)
Sleep(1);
}
EnterCriticalSection(&mutex->cs);
return 0;
}
static inline int pthread_mutex_unlock(pthread_mutex_t *const mutex) {
ReleaseSRWLockExclusive(mutex);
LeaveCriticalSection(&mutex->cs);
return 0;
}
static inline int pthread_cond_init(pthread_cond_t *const cond,
const void *const attr)
{
InitializeConditionVariable(cond);
InitializeCriticalSection(&cond->cs);
cond->head = NULL;
return 0;
}
static inline int pthread_cond_destroy(pthread_cond_t *const cond) {
DeleteCriticalSection(&cond->cs);
return 0;
}
static inline int pthread_cond_wait(pthread_cond_t *const cond,
pthread_mutex_t *const mutex)
{
return !SleepConditionVariableSRW(cond, mutex, INFINITE, 0);
}
static inline int pthread_cond_signal(pthread_cond_t *const cond) {
WakeConditionVariable(cond);
return 0;
}
static inline int pthread_cond_broadcast(pthread_cond_t *const cond) {
WakeAllConditionVariable(cond);
return 0;
}
#define pthread_cond_wait dav1d_pthread_cond_wait
#define pthread_cond_signal dav1d_pthread_cond_signal
#define pthread_cond_broadcast dav1d_pthread_cond_broadcast
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond);
#else

View file

@ -85,15 +85,73 @@ COLD int dav1d_pthread_join(pthread_t *const thread, void **const res) {
COLD int dav1d_pthread_once(pthread_once_t *const once_control,
void (*const init_routine)(void))
{
BOOL pending = FALSE;
if (InitOnceBeginInitialize(once_control, 0, &pending, NULL) != TRUE)
return 1;
if (pending == TRUE)
if (InterlockedCompareExchange(once_control, 1, 0) == 0) {
init_routine();
InterlockedExchange(once_control, 2);
} else {
while (InterlockedCompareExchange(once_control, 2, 2) != 2)
Sleep(1);
}
return 0;
}
return !InitOnceComplete(once_control, 0, NULL);
/* Each waiter owns an event. Queue operations and signalling share a lock,
* so a new waiter cannot consume an earlier waiter's notification. */
struct dav1d_cond_waiter {
HANDLE event;
struct dav1d_cond_waiter *next;
};
int dav1d_pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) {
struct dav1d_cond_waiter waiter, **link;
DWORD result;
waiter.event = CreateEventW(NULL, FALSE, FALSE, NULL);
if (!waiter.event) return 1;
EnterCriticalSection(&cond->cs);
waiter.next = NULL;
for (link = &cond->head; *link; link = &(*link)->next) {}
*link = &waiter;
pthread_mutex_unlock(mutex);
LeaveCriticalSection(&cond->cs);
result = WaitForSingleObject(waiter.event, INFINITE);
EnterCriticalSection(&cond->cs);
/* Also unlink on wait failure before the stack record goes away. */
for (link = &cond->head; *link; link = &(*link)->next) {
if (*link == &waiter) {
*link = waiter.next;
break;
}
}
CloseHandle(waiter.event);
LeaveCriticalSection(&cond->cs);
pthread_mutex_lock(mutex);
return result != WAIT_OBJECT_0;
}
int dav1d_pthread_cond_signal(pthread_cond_t *cond) {
int result = 0;
EnterCriticalSection(&cond->cs);
if (cond->head) {
if (SetEvent(cond->head->event)) cond->head = cond->head->next;
else result = 1;
}
LeaveCriticalSection(&cond->cs);
return result;
}
int dav1d_pthread_cond_broadcast(pthread_cond_t *cond) {
int result = 0;
EnterCriticalSection(&cond->cs);
while (cond->head) {
if (!SetEvent(cond->head->event)) {
result = 1;
break;
}
cond->head = cond->head->next;
}
LeaveCriticalSection(&cond->cs);
return result;
}
#endif

View file

@ -47,6 +47,9 @@ if CONFIG['CC_TYPE'] == 'gcc':
OS_LIBS += ['gomp']
if CONFIG['OS_ARCH'] == 'WINNT':
OS_LIBS += ['dl']
elif CONFIG['CLANG_CL']:
# clang-cl lowers OpenMP pragmas to the LLVM OpenMP runtime.
CXXFLAGS += ['-fopenmp']
DEFINES['BUILDING_SOUNDTOUCH'] = 1

View file

@ -39,11 +39,12 @@ if CONFIG['OS_TARGET'] != 'Android':
DEFINES['FAKE_LOG_DEVICE'] = True
SOURCES += [
'system/core/liblog/fake_log_device.c',
# io.h conflicts with the access stub in logd_write.c on Windows.
'system/core/liblog/logprint.c',
]
UNIFIED_SOURCES += [
'system/core/libcutils/strdup16to8.c',
'system/core/liblog/logd_write.c',
'system/core/liblog/logprint.c',
]
EXPORTS.mp4_demuxer += [

View file

@ -26,6 +26,12 @@
#include <assert.h>
#include <arpa/inet.h>
#ifdef _WIN32
#include <io.h>
#else
#include <unistd.h>
#endif
#include <log/logd.h>
#include <log/logprint.h>
@ -945,7 +951,11 @@ int android_log_printLogLine(
return -1;
do {
#ifdef _WIN32
ret = _write(fd, outBuffer, totalLen);
#else
ret = write(fd, outBuffer, totalLen);
#endif
} while (ret < 0 && errno == EINTR);
if (ret < 0) {