diff options
Diffstat (limited to 'osdep')
83 files changed, 4559 insertions, 4201 deletions
diff --git a/osdep/atomic.h b/osdep/atomic.h deleted file mode 100644 index 774924afa2..0000000000 --- a/osdep/atomic.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - * This file is part of mpv. - * Copyright (c) 2013 Stefano Pigozzi <stefano.pigozzi@gmail.com> - * - * mpv is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * mpv is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with mpv. If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef MP_ATOMIC_H -#define MP_ATOMIC_H - -#include <inttypes.h> -#include "config.h" - -#if HAVE_STDATOMIC -#include <stdatomic.h> -typedef _Atomic float mp_atomic_float; -typedef _Atomic int64_t mp_atomic_int64; -typedef _Atomic uint64_t mp_atomic_uint64; -#else - -// Emulate the parts of C11 stdatomic.h needed by mpv. - -typedef struct { unsigned long v; } atomic_ulong; -typedef struct { int v; } atomic_int; -typedef struct { unsigned int v; } atomic_uint; -typedef struct { _Bool v; } atomic_bool; -typedef struct { long long v; } atomic_llong; -typedef struct { uint_least32_t v; } atomic_uint_least32_t; -typedef struct { unsigned long long v; } atomic_ullong; - -typedef struct { float v; } mp_atomic_float; -typedef struct { int64_t v; } mp_atomic_int64; -typedef struct { uint64_t v; } mp_atomic_uint64; - -#define ATOMIC_VAR_INIT(x) \ - {.v = (x)} - -#define memory_order_relaxed 1 -#define memory_order_seq_cst 2 -#define memory_order_acq_rel 3 - -#include <pthread.h> - -extern pthread_mutex_t mp_atomic_mutex; - -#define atomic_load(p) \ - ({ __typeof__(p) p_ = (p); \ - pthread_mutex_lock(&mp_atomic_mutex); \ - __typeof__(p_->v) v_ = p_->v; \ - pthread_mutex_unlock(&mp_atomic_mutex); \ - v_; }) -#define atomic_store(p, val) \ - ({ __typeof__(val) val_ = (val); \ - __typeof__(p) p_ = (p); \ - pthread_mutex_lock(&mp_atomic_mutex); \ - p_->v = val_; \ - pthread_mutex_unlock(&mp_atomic_mutex); }) -#define atomic_fetch_op(a, b, op) \ - ({ __typeof__(a) a_ = (a); \ - __typeof__(b) b_ = (b); \ - pthread_mutex_lock(&mp_atomic_mutex); \ - __typeof__(a_->v) v_ = a_->v; \ - a_->v = v_ op b_; \ - pthread_mutex_unlock(&mp_atomic_mutex); \ - v_; }) -#define atomic_fetch_add(a, b) atomic_fetch_op(a, b, +) -#define atomic_fetch_and(a, b) atomic_fetch_op(a, b, &) -#define atomic_fetch_or(a, b) atomic_fetch_op(a, b, |) -#define atomic_exchange(p, new) \ - ({ __typeof__(p) p_ = (p); \ - pthread_mutex_lock(&mp_atomic_mutex); \ - __typeof__(p_->v) res_ = p_->v; \ - p_->v = (new); \ - pthread_mutex_unlock(&mp_atomic_mutex); \ - res_; }) -#define atomic_compare_exchange_strong(p, old, new) \ - ({ __typeof__(p) p_ = (p); \ - __typeof__(old) old_ = (old); \ - __typeof__(new) new_ = (new); \ - pthread_mutex_lock(&mp_atomic_mutex); \ - int res_ = p_->v == *old_; \ - if (res_) { \ - p_->v = new_; \ - } else { \ - *old_ = p_->v; \ - } \ - pthread_mutex_unlock(&mp_atomic_mutex); \ - res_; }) - -#define atomic_load_explicit(a, b) \ - atomic_load(a) - -#define atomic_exchange_explicit(a, b, c) \ - atomic_exchange(a, b) - -#endif /* else HAVE_STDATOMIC */ - -#endif diff --git a/osdep/compiler.h b/osdep/compiler.h index 7c9f859f3a..f5658979e3 100644 --- a/osdep/compiler.h +++ b/osdep/compiler.h @@ -6,9 +6,13 @@ #ifdef __GNUC__ #define PRINTF_ATTRIBUTE(a1, a2) __attribute__ ((format(printf, a1, a2))) #define MP_NORETURN __attribute__((noreturn)) +#define MP_FALLTHROUGH __attribute__((fallthrough)) +#define MP_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) #else #define PRINTF_ATTRIBUTE(a1, a2) #define MP_NORETURN +#define MP_FALLTHROUGH do {} while (0) +#define MP_WARN_UNUSED_RESULT #endif // Broken crap with __USE_MINGW_ANSI_STDIO @@ -17,10 +21,10 @@ #define PRINTF_ATTRIBUTE(a1, a2) __attribute__ ((format (gnu_printf, a1, a2))) #endif -#if __STDC_VERSION__ >= 201112L -#include <stdalign.h> +#ifdef __GNUC__ +#define MP_ASSERT_UNREACHABLE() (assert(!"unreachable"), __builtin_unreachable()) #else -#define alignof(x) (offsetof(struct {char unalign_; x u;}, u)) +#define MP_ASSERT_UNREACHABLE() (assert(!"unreachable"), abort()) #endif #endif diff --git a/osdep/io.c b/osdep/io.c index d4dcfc6fba..21abe0e1d5 100644 --- a/osdep/io.c +++ b/osdep/io.c @@ -32,6 +32,7 @@ #include "mpv_talloc.h" #include "config.h" +#include "misc/random.h" #include "osdep/io.h" #include "osdep/terminal.h" @@ -145,7 +146,7 @@ char *mp_to_utf8(void *talloc_ctx, const wchar_t *s) #include <io.h> #include <fcntl.h> -#include <pthread.h> +#include "osdep/threads.h" static void set_errno_from_lasterror(void) { @@ -188,7 +189,7 @@ static bool get_file_ids_win8(HANDLE h, dev_t *dev, ino_t *ino) // SDK, but we can ignore that by just memcpying it. This will also // truncate the file ID on 32-bit Windows, which doesn't support __int128. // 128-bit file IDs are only used for ReFS, so that should be okay. - assert(sizeof(*ino) <= sizeof(ii.FileId)); + static_assert(sizeof(*ino) <= sizeof(ii.FileId), ""); memcpy(ino, &ii.FileId, sizeof(*ino)); return true; } @@ -297,62 +298,53 @@ int mp_fstat(int fd, struct mp_stat *buf) return hstat(h, buf); } -#if HAVE_UWP -static int mp_vfprintf(FILE *stream, const char *format, va_list args) -{ - return vfprintf(stream, format, args); -} -#else -static int mp_check_console(HANDLE wstream) +static inline HANDLE get_handle(FILE *stream) { - if (wstream != INVALID_HANDLE_VALUE) { - unsigned int filetype = GetFileType(wstream); + HANDLE wstream = INVALID_HANDLE_VALUE; - if (!((filetype == FILE_TYPE_UNKNOWN) && - (GetLastError() != ERROR_SUCCESS))) - { - filetype &= ~(FILE_TYPE_REMOTE); + if (stream == stdout || stream == stderr) { + wstream = GetStdHandle(stream == stdout ? + STD_OUTPUT_HANDLE : STD_ERROR_HANDLE); + } + return wstream; +} - if (filetype == FILE_TYPE_CHAR) { - DWORD ConsoleMode; - int ret = GetConsoleMode(wstream, &ConsoleMode); +size_t mp_fwrite(const void *restrict buffer, size_t size, size_t count, + FILE *restrict stream) +{ + if (!size || !count) + return 0; - if (!(!ret && (GetLastError() == ERROR_INVALID_HANDLE))) { - // This seems to be a console - return 1; - } - } + HANDLE wstream = get_handle(stream); + if (mp_check_console(wstream)) { + unsigned char *start = (unsigned char *)buffer; + size_t c = 0; + for (; c < count; ++c) { + if (mp_console_write(wstream, (bstr){start, size}) <= 0) + break; + start += size; } + return c; } - return 0; +#undef fwrite + return fwrite(buffer, size, count, stream); } +#if HAVE_UWP static int mp_vfprintf(FILE *stream, const char *format, va_list args) { - int done = 0; - - HANDLE wstream = INVALID_HANDLE_VALUE; - - if (stream == stdout || stream == stderr) { - wstream = GetStdHandle(stream == stdout ? - STD_OUTPUT_HANDLE : STD_ERROR_HANDLE); - } - - if (mp_check_console(wstream)) { - size_t len = vsnprintf(NULL, 0, format, args) + 1; - char *buf = talloc_array(NULL, char, len); + return vfprintf(stream, format, args); +} +#else - if (buf) { - done = vsnprintf(buf, len, format, args); - mp_write_console_ansi(wstream, buf); - } - talloc_free(buf); - } else { - done = vfprintf(stream, format, args); - } +static int mp_vfprintf(FILE *stream, const char *format, va_list args) +{ + HANDLE wstream = get_handle(stream); + if (mp_check_console(wstream)) + return mp_console_vfprintf(wstream, format, args); - return done; + return vfprintf(stream, format, args); } #endif @@ -483,6 +475,20 @@ int mp_creat(const char *filename, int mode) return mp_open(filename, _O_CREAT | _O_WRONLY | _O_TRUNC, mode); } +int mp_rename(const char *oldpath, const char *newpath) +{ + wchar_t *woldpath = mp_from_utf8(NULL, oldpath), + *wnewpath = mp_from_utf8(NULL, newpath); + BOOL ok = MoveFileExW(woldpath, wnewpath, MOVEFILE_REPLACE_EXISTING); + talloc_free(woldpath); + talloc_free(wnewpath); + if (!ok) { + set_errno_from_lasterror(); + return -1; + } + return 0; +} + FILE *mp_fopen(const char *filename, const char *mode) { if (!mode[0]) { @@ -543,7 +549,9 @@ FILE *mp_fopen(const char *filename, const char *mode) // Thus we need MP_PATH_MAX as the UTF-8/char version of PATH_MAX. // Also make sure there's free space for the terminating \0. // (For codepoints encoded as UTF-16 surrogate pairs, UTF-8 has the same length.) -#define MP_PATH_MAX (FILENAME_MAX * 3 + 1) +// Lastly, note that neither _wdirent nor WIN32_FIND_DATA can store filenames +// longer than this, so long-path support for readdir() is impossible. +#define MP_FILENAME_MAX (FILENAME_MAX * 3 + 1) struct mp_dir { DIR crap; // must be first member @@ -553,9 +561,9 @@ struct mp_dir { // dirent has space only for FILENAME_MAX bytes. _wdirent has space for // FILENAME_MAX wchar_t, which might end up bigger as UTF-8 in some // cases. Guarantee we can always hold _wdirent.d_name converted to - // UTF-8 (see MP_PATH_MAX). + // UTF-8 (see above). // This works because dirent.d_name is the last member of dirent. - char space[MP_PATH_MAX]; + char space[MP_FILENAME_MAX]; }; }; @@ -605,6 +613,14 @@ int mp_mkdir(const char *path, int mode) return res; } +int mp_unlink(const char *path) +{ + wchar_t *wpath = mp_from_utf8(NULL, path); + int res = _wunlink(wpath); + talloc_free(wpath); + return res; +} + char *mp_win32_getcwd(char *buf, size_t size) { if (size >= SIZE_MAX / 3 - 1) { @@ -669,8 +685,8 @@ static void init_getenv(void) char *mp_getenv(const char *name) { - static pthread_once_t once_init_getenv = PTHREAD_ONCE_INIT; - pthread_once(&once_init_getenv, init_getenv); + static mp_once once_init_getenv = MP_STATIC_ONCE_INITIALIZER; + mp_exec_once(&once_init_getenv, init_getenv); // Copied from musl, http://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // Copyright © 2005-2013 Rich Felker, standard MIT license int i; @@ -682,7 +698,7 @@ char *mp_getenv(const char *name) return NULL; } -char ***mp_penviron() +char ***mp_penviron(void) { mp_getenv(""); // ensure init return &utf8_environ; // `environ' should be an l-value @@ -698,6 +714,90 @@ off_t mp_lseek(int fd, off_t offset, int whence) return _lseeki64(fd, offset, whence); } +_Thread_local +static struct { + DWORD errcode; + char *errstring; +} mp_dl_result = { + .errcode = 0, + .errstring = NULL +}; + +static void mp_dl_free(void) +{ + if (mp_dl_result.errstring != NULL) { + talloc_free(mp_dl_result.errstring); + } +} + +static void mp_dl_init(void) +{ + atexit(mp_dl_free); +} + +void *mp_dlopen(const char *filename, int flag) +{ + HMODULE lib = NULL; + void *ta_ctx = talloc_new(NULL); + wchar_t *wfilename = mp_from_utf8(ta_ctx, filename); + + DWORD len = GetFullPathNameW(wfilename, 0, NULL, NULL); + if (!len) + goto err; + + wchar_t *path = talloc_array(ta_ctx, wchar_t, len); + len = GetFullPathNameW(wfilename, len, path, NULL); + if (!len) + goto err; + + lib = LoadLibraryW(path); + +err: + talloc_free(ta_ctx); + mp_dl_result.errcode = GetLastError(); + return (void *)lib; +} + +void *mp_dlsym(void *handle, const char *symbol) +{ + FARPROC addr = GetProcAddress((HMODULE)handle, symbol); + mp_dl_result.errcode = GetLastError(); + return (void *)addr; +} + +char *mp_dlerror(void) +{ + static mp_once once_init_dlerror = MP_STATIC_ONCE_INITIALIZER; + mp_exec_once(&once_init_dlerror, mp_dl_init); + mp_dl_free(); + + if (mp_dl_result.errcode == 0) + return NULL; + + // convert error code to a string message + LPWSTR werrstring = NULL; + FormatMessageW( + FORMAT_MESSAGE_FROM_SYSTEM + | FORMAT_MESSAGE_IGNORE_INSERTS + | FORMAT_MESSAGE_ALLOCATE_BUFFER, + NULL, + mp_dl_result.errcode, + MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), + (LPWSTR) &werrstring, + 0, + NULL); + mp_dl_result.errcode = 0; + + if (werrstring) { + mp_dl_result.errstring = mp_to_utf8(NULL, werrstring); + LocalFree(werrstring); + } + + return mp_dl_result.errstring == NULL + ? "unknown error" + : mp_dl_result.errstring; +} + #if HAVE_UWP void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) { @@ -791,29 +891,3 @@ void freelocale(locale_t locobj) } #endif // __MINGW32__ - -int mp_mkostemps(char *template, int suffixlen, int flags) -{ - size_t len = strlen(template); - char *t = len >= 6 + suffixlen ? &template[len - (6 + suffixlen)] : NULL; - if (!t || strncmp(t, "XXXXXX", 6) != 0) { - errno = EINVAL; - return -1; - } - - for (size_t fuckshit = 0; fuckshit < UINT32_MAX; fuckshit++) { - // Using a random value may make it require fewer iterations (even if - // not truly random; just a counter would be sufficient). - size_t fuckmess = rand(); - char crap[7] = ""; - snprintf(crap, sizeof(crap), " |