/tools/windeps/libxml2*
/tools/windeps/mingw*
/tools/windeps/sysroot_*
-/tools/windeps/winpthreads*
/wimlib-*-bin/
/wimlib-*.tar
/wimlib-*.tar.*
src/tagged_items.c \
src/template.c \
src/textfile.c \
+ src/threads.c \
src/timestamp.c \
src/update_image.c \
src/util.c \
include/wimlib/solid.h \
include/wimlib/tagged_items.h \
include/wimlib/textfile.h \
+ include/wimlib/threads.h \
include/wimlib/timestamp.h \
include/wimlib/types.h \
include/wimlib/unaligned.h \
Removed support for Windows XP.
+ On Windows, wimlib no longer depends on winpthreads.
+
Fixed a bug in 'wimsplit' where it didn't accept part sizes of 4 GiB or
larger on Windows and on 32-bit platforms.
- mingw64-x86_64-binutils
- mingw64-x86_64-gcc-g++
- mingw64-x86_64-libxml2
- - mingw64-x86_64-winpthreads
- pkg-config
Download wimlib's source code from https://wimlib.net/downloads/wimlib-1.13.6.tar.gz.
libwim-15.dll will be linked to several other DLLs which you will need as well:
- - libwinpthread-1.dll
- libxml2-2.dll, which also requires:
- iconv.dll
- liblzma-5.dll
./bootstrap
./tools/make-windows-release x86_64
-The release script will download and build libxml2 and winpthreads as static
-libraries, then build wimlib, then do some final tasks and bundle the resulting
-files up into a ZIP archive. If successful you'll end up with a file like
+The release script will download and build libxml2 as a static library, then
+build wimlib, then do some final tasks and bundle the resulting files up into a
+ZIP archive. If successful you'll end up with a file like
"wimlib-1.13.6-windows-x86_64-bin.zip", just like the official releases. For
32-bit binaries just use "i686" instead of "x86_64".
###############################################################################
# ------------------------------ pthreads -------------------------------------
-AX_PTHREAD([], [AC_MSG_ERROR(["cannot find pthreads library"])])
+if test "$WINDOWS_NATIVE_BUILD" != "yes"; then
+ AX_PTHREAD([], [AC_MSG_ERROR(["cannot find pthreads library"])])
+fi
# ------------------------------ libxml2 --------------------------------------
PKG_CHECK_MODULES([LIBXML2], [libxml-2.0])
--- /dev/null
+#ifndef _WIMLIB_THREADS_H
+#define _WIMLIB_THREADS_H
+
+#include <stdbool.h>
+
+#ifdef _WIN32
+
+struct thread {
+ void *win32_thread;
+ void *(*thrproc)(void *);
+ void *arg;
+};
+
+struct mutex { void *win32_crit; };
+#define MUTEX_INITIALIZER { NULL }
+
+struct condvar { void *win32_cond; };
+
+#else /* _WIN32 */
+
+#include <pthread.h>
+
+struct thread { pthread_t pthread; };
+
+struct mutex { pthread_mutex_t pthread_mutex; };
+#define MUTEX_INITIALIZER { PTHREAD_MUTEX_INITIALIZER }
+
+struct condvar { pthread_cond_t pthread_cond; };
+
+#endif /* !_WIN32 */
+
+bool thread_create(struct thread *t, void *(*thrproc)(void *), void *arg);
+void thread_join(struct thread *t);
+bool mutex_init(struct mutex *m);
+void mutex_destroy(struct mutex *m);
+void mutex_lock(struct mutex *m);
+void mutex_unlock(struct mutex *m);
+bool condvar_init(struct condvar *c);
+void condvar_destroy(struct condvar *c);
+void condvar_wait(struct condvar *c, struct mutex *m);
+void condvar_signal(struct condvar *c);
+void condvar_broadcast(struct condvar *c);
+
+#endif /* _WIMLIB_THREADS_H */
#endif
#include <errno.h>
-#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include "wimlib/chunk_compressor.h"
#include "wimlib/error.h"
#include "wimlib/list.h"
+#include "wimlib/threads.h"
#include "wimlib/util.h"
struct message_queue {
struct list_head list;
- pthread_mutex_t lock;
- pthread_cond_t msg_avail_cond;
- pthread_cond_t space_avail_cond;
+ struct mutex lock;
+ struct condvar msg_avail_cond;
+ struct condvar space_avail_cond;
bool terminating;
};
struct compressor_thread_data {
- pthread_t thread;
+ struct thread thread;
struct message_queue *chunks_to_compress_queue;
struct message_queue *compressed_chunks_queue;
struct wimlib_compressor *compressor;
static int
message_queue_init(struct message_queue *q)
{
- if (pthread_mutex_init(&q->lock, NULL)) {
- ERROR_WITH_ERRNO("Failed to initialize mutex");
+ if (!mutex_init(&q->lock))
goto err;
- }
- if (pthread_cond_init(&q->msg_avail_cond, NULL)) {
- ERROR_WITH_ERRNO("Failed to initialize condition variable");
+ if (!condvar_init(&q->msg_avail_cond))
goto err_destroy_lock;
- }
- if (pthread_cond_init(&q->space_avail_cond, NULL)) {
- ERROR_WITH_ERRNO("Failed to initialize condition variable");
+ if (!condvar_init(&q->space_avail_cond))
goto err_destroy_msg_avail_cond;
- }
INIT_LIST_HEAD(&q->list);
return 0;
err_destroy_msg_avail_cond:
- pthread_cond_destroy(&q->msg_avail_cond);
+ condvar_destroy(&q->msg_avail_cond);
err_destroy_lock:
- pthread_mutex_destroy(&q->lock);
+ mutex_destroy(&q->lock);
err:
return WIMLIB_ERR_NOMEM;
}
message_queue_destroy(struct message_queue *q)
{
if (q->list.next != NULL) {
- pthread_mutex_destroy(&q->lock);
- pthread_cond_destroy(&q->msg_avail_cond);
- pthread_cond_destroy(&q->space_avail_cond);
+ mutex_destroy(&q->lock);
+ condvar_destroy(&q->msg_avail_cond);
+ condvar_destroy(&q->space_avail_cond);
}
}
static void
message_queue_put(struct message_queue *q, struct message *msg)
{
- pthread_mutex_lock(&q->lock);
+ mutex_lock(&q->lock);
list_add_tail(&msg->list, &q->list);
- pthread_cond_signal(&q->msg_avail_cond);
- pthread_mutex_unlock(&q->lock);
+ condvar_signal(&q->msg_avail_cond);
+ mutex_unlock(&q->lock);
}
static struct message *
{
struct message *msg;
- pthread_mutex_lock(&q->lock);
+ mutex_lock(&q->lock);
while (list_empty(&q->list) && !q->terminating)
- pthread_cond_wait(&q->msg_avail_cond, &q->lock);
+ condvar_wait(&q->msg_avail_cond, &q->lock);
if (!q->terminating) {
msg = list_entry(q->list.next, struct message, list);
list_del(&msg->list);
} else
msg = NULL;
- pthread_mutex_unlock(&q->lock);
+ mutex_unlock(&q->lock);
return msg;
}
static void
message_queue_terminate(struct message_queue *q)
{
- pthread_mutex_lock(&q->lock);
+ mutex_lock(&q->lock);
q->terminating = true;
- pthread_cond_broadcast(&q->msg_avail_cond);
- pthread_mutex_unlock(&q->lock);
+ condvar_broadcast(&q->msg_avail_cond);
+ mutex_unlock(&q->lock);
}
static int
message_queue_terminate(&ctx->chunks_to_compress_queue);
for (i = 0; i < ctx->num_started_threads; i++)
- pthread_join(ctx->thread_data[i].thread, NULL);
+ thread_join(&ctx->thread_data[i].thread);
}
message_queue_destroy(&ctx->chunks_to_compress_queue);
ctx->num_started_threads < num_threads;
ctx->num_started_threads++)
{
- ret = pthread_create(&ctx->thread_data[ctx->num_started_threads].thread,
- NULL,
- compressor_thread_proc,
- &ctx->thread_data[ctx->num_started_threads]);
- if (ret) {
- errno = ret;
- WARNING_WITH_ERRNO("Failed to create compressor thread %u of %u",
- ctx->num_started_threads + 1,
- num_threads);
+ if (!thread_create(&ctx->thread_data[ctx->num_started_threads].thread,
+ compressor_thread_proc,
+ &ctx->thread_data[ctx->num_started_threads]))
+ {
ret = WIMLIB_ERR_NOMEM;
if (ctx->num_started_threads >= 2)
break;
#include <fuse.h>
#include <limits.h>
#include <mqueue.h>
-#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include "wimlib/paths.h"
#include "wimlib/progress.h"
#include "wimlib/reparse.h"
+#include "wimlib/threads.h"
#include "wimlib/timestamp.h"
#include "wimlib/unix_data.h"
#include "wimlib/write.h"
struct wimfs_unmount_info unmount_info;
mqd_t mq;
struct commit_progress_thread_args args;
- pthread_t commit_progress_tid;
+ struct thread commit_progress_tid;
int ret;
memset(&unmount_info, 0, sizeof(unmount_info));
args.mq = mq;
args.progfunc = progfunc;
args.progctx = progctx;
- ret = pthread_create(&commit_progress_tid, NULL,
- commit_progress_thread_proc, &args);
- if (ret) {
- errno = ret;
- ERROR_WITH_ERRNO("Can't create thread");
+ if (!thread_create(&commit_progress_tid,
+ commit_progress_thread_proc, &args)) {
ret = WIMLIB_ERR_NOMEM;
goto out_delete_mq;
}
/* Terminate the progress thread. */
char empty[1];
mq_send(mq, empty, 0, 1);
- pthread_join(commit_progress_tid, NULL);
+ thread_join(&commit_progress_tid);
}
out_delete_mq:
if (progfunc) {
--- /dev/null
+/*
+ * thread.c - Thread, mutex, and condition variable support. Wraps around
+ * pthreads or Windows native threads.
+ */
+
+/*
+ * Copyright 2016-2023 Eric Biggers
+ *
+ * This file 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 3 of the License, or (at your option) any
+ * later version.
+ *
+ * This file 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 this file; if not, see http://www.gnu.org/licenses/.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifdef _WIN32
+# include "wimlib/win32_common.h"
+#else
+# include <errno.h>
+# include <pthread.h>
+#endif
+
+#include "wimlib/assert.h"
+#include "wimlib/error.h"
+#include "wimlib/threads.h"
+#include "wimlib/util.h"
+
+#ifdef _WIN32
+
+static WINAPI DWORD
+win32_thrproc(LPVOID lpParameter)
+{
+ struct thread *t = (struct thread *)lpParameter;
+
+ (*t->thrproc)(t->arg);
+ return 0;
+}
+
+bool thread_create(struct thread *t, void *(*thrproc)(void *), void *arg)
+{
+ HANDLE h;
+
+ t->thrproc = thrproc;
+ t->arg = arg;
+ h = CreateThread(NULL, 0, win32_thrproc, (LPVOID)t, 0, NULL);
+ if (h == NULL) {
+ win32_error(GetLastError(), L"Failed to create thread");
+ return false;
+ }
+ t->win32_thread = (void *)h;
+ return true;
+}
+
+void thread_join(struct thread *t)
+{
+ DWORD res = WaitForSingleObject((HANDLE)t->win32_thread, INFINITE);
+
+ wimlib_assert(res == WAIT_OBJECT_0);
+}
+
+bool mutex_init(struct mutex *m)
+{
+ CRITICAL_SECTION *crit = MALLOC(sizeof(*crit));
+
+ if (!crit)
+ return false;
+ InitializeCriticalSection(crit);
+ m->win32_crit = crit;
+ return true;
+}
+
+void mutex_destroy(struct mutex *m)
+{
+ DeleteCriticalSection(m->win32_crit);
+ FREE(m->win32_crit);
+ m->win32_crit = NULL;
+}
+
+void mutex_lock(struct mutex *m)
+{
+ CRITICAL_SECTION *crit = m->win32_crit;
+
+ if (unlikely(!crit)) {
+ CRITICAL_SECTION *old;
+
+ crit = MALLOC(sizeof(*crit));
+ wimlib_assert(crit != NULL);
+ InitializeCriticalSection(crit);
+ old = InterlockedCompareExchangePointer(&m->win32_crit, crit,
+ NULL);
+ if (old) {
+ DeleteCriticalSection(crit);
+ FREE(crit);
+ crit = old;
+ }
+ }
+ EnterCriticalSection(crit);
+}
+
+void mutex_unlock(struct mutex *m)
+{
+ LeaveCriticalSection(m->win32_crit);
+}
+
+bool condvar_init(struct condvar *c)
+{
+ CONDITION_VARIABLE *cond = MALLOC(sizeof(*cond));
+
+ if (!cond)
+ return false;
+ InitializeConditionVariable(cond);
+ c->win32_cond = cond;
+ return true;
+}
+
+void condvar_destroy(struct condvar *c)
+{
+ FREE(c->win32_cond);
+ c->win32_cond = NULL;
+}
+
+void condvar_wait(struct condvar *c, struct mutex *m)
+{
+ BOOL ok = SleepConditionVariableCS(c->win32_cond, m->win32_crit,
+ INFINITE);
+ wimlib_assert(ok);
+}
+
+void condvar_signal(struct condvar *c)
+{
+ WakeConditionVariable(c->win32_cond);
+}
+
+void condvar_broadcast(struct condvar *c)
+{
+ WakeAllConditionVariable(c->win32_cond);
+}
+
+#else /* _WIN32 */
+
+bool thread_create(struct thread *t, void *(*thrproc)(void *), void *arg)
+{
+ int err = pthread_create(&t->pthread, NULL, thrproc, arg);
+
+ if (err) {
+ errno = err;
+ ERROR_WITH_ERRNO("Failed to create thread");
+ return false;
+ }
+ return true;
+}
+
+void thread_join(struct thread *t)
+{
+ int err = pthread_join(t->pthread, NULL);
+
+ wimlib_assert(err == 0);
+}
+
+bool mutex_init(struct mutex *m)
+{
+ int err = pthread_mutex_init(&m->pthread_mutex, NULL);
+
+ if (err) {
+ errno = err;
+ ERROR_WITH_ERRNO("Failed to initialize mutex");
+ return false;
+ }
+ return true;
+}
+
+void mutex_destroy(struct mutex *m)
+{
+ int err = pthread_mutex_destroy(&m->pthread_mutex);
+
+ wimlib_assert(err == 0);
+}
+
+void mutex_lock(struct mutex *m)
+{
+ int err = pthread_mutex_lock(&m->pthread_mutex);
+
+ wimlib_assert(err == 0);
+}
+
+void mutex_unlock(struct mutex *m)
+{
+ int err = pthread_mutex_unlock(&m->pthread_mutex);
+
+ wimlib_assert(err == 0);
+}
+
+bool condvar_init(struct condvar *c)
+{
+ int err = pthread_cond_init(&c->pthread_cond, NULL);
+
+ if (err) {
+ errno = err;
+ ERROR_WITH_ERRNO("Failed to initialize condition variable");
+ return false;
+ }
+ return true;
+}
+
+void condvar_destroy(struct condvar *c)
+{
+ int err = pthread_cond_destroy(&c->pthread_cond);
+
+ wimlib_assert(err == 0);
+}
+
+void condvar_wait(struct condvar *c, struct mutex *m)
+{
+ int err = pthread_cond_wait(&c->pthread_cond, &m->pthread_mutex);
+
+ wimlib_assert(err == 0);
+}
+
+void condvar_signal(struct condvar *c)
+{
+ int err = pthread_cond_signal(&c->pthread_cond);
+
+ wimlib_assert(err == 0);
+}
+
+void condvar_broadcast(struct condvar *c)
+{
+ int err = pthread_cond_broadcast(&c->pthread_cond);
+
+ wimlib_assert(err == 0);
+}
+
+#endif /* !_WIN32 */
#include <errno.h>
#include <fcntl.h>
-#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
#include "wimlib/integrity.h"
#include "wimlib/metadata.h"
#include "wimlib/security.h"
+#include "wimlib/threads.h"
#include "wimlib/wim.h"
#include "wimlib/xml.h"
#include "wimlib/win32.h"
}
static bool lib_initialized = false;
-static pthread_mutex_t lib_initialization_mutex = PTHREAD_MUTEX_INITIALIZER;
+static struct mutex lib_initialization_mutex = MUTEX_INITIALIZER;
/* API function documented in wimlib.h */
WIMLIBAPI int
if (lib_initialized)
goto out;
- pthread_mutex_lock(&lib_initialization_mutex);
+ mutex_lock(&lib_initialization_mutex);
if (lib_initialized)
goto out_unlock;
lib_initialized = true;
ret = 0;
out_unlock:
- pthread_mutex_unlock(&lib_initialization_mutex);
+ mutex_unlock(&lib_initialization_mutex);
out:
return ret;
}
if (!lib_initialized)
return;
- pthread_mutex_lock(&lib_initialization_mutex);
+ mutex_lock(&lib_initialization_mutex);
if (!lib_initialized)
goto out_unlock;
lib_initialized = false;
out_unlock:
- pthread_mutex_unlock(&lib_initialization_mutex);
+ mutex_unlock(&lib_initialization_mutex);
}
#include "wimlib/win32_common.h"
#include <cguid.h>
-#include <pthread.h>
#include "wimlib/error.h"
+#include "wimlib/threads.h"
#include "wimlib/util.h"
#include "wimlib/win32_vss.h"
*----------------------------------------------------------------------------*/
static bool vss_initialized;
-static pthread_mutex_t vss_initialization_mutex = PTHREAD_MUTEX_INITIALIZER;
+static struct mutex vss_initialization_mutex = MUTEX_INITIALIZER;
/* vssapi.dll */
static HANDLE hVssapi;
if (vss_initialized)
return true;
- pthread_mutex_lock(&vss_initialization_mutex);
+ mutex_lock(&vss_initialization_mutex);
if (!vss_initialized)
vss_initialized = vss_global_init_impl();
- pthread_mutex_unlock(&vss_initialization_mutex);
+ mutex_unlock(&vss_initialization_mutex);
if (vss_initialized)
return true;
if (!vss_initialized)
return;
- pthread_mutex_lock(&vss_initialization_mutex);
+ mutex_lock(&vss_initialization_mutex);
if (vss_initialized) {
(*func_CoUninitialize)();
FreeLibrary(hOle32);
FreeLibrary(hVssapi);
vss_initialized = false;
}
- pthread_mutex_unlock(&vss_initialization_mutex);
+ mutex_unlock(&vss_initialization_mutex);
}
/*----------------------------------------------------------------------------*
#
ARCHITECTURES := i686 x86_64
-LIBXML2_VERSION := 2.10.3
-WINPTHREADS_VERSION := 10.0.0
+LIBXML2_VERSION := 2.10.3
LIBXML_URL := https://download.gnome.org/sources/libxml2/2.10/libxml2-$(LIBXML2_VERSION).tar.xz
-WINPTHREADS_URL := http://downloads.sourceforge.net/mingw-w64/mingw-w64/mingw-w64-release/mingw-w64-v$(WINPTHREADS_VERSION).tar.bz2
-
-
LIBXML_SRCDIR := libxml2-$(LIBXML2_VERSION)
LIBXML_DIST := $(LIBXML_SRCDIR).tar.xz
SRCDIR_TARGETS += $(LIBXML_SRCDIR)
cp $@/Copyright COPYING.libxml2
MAKE_CLEAN_FILES += $(LIBXML_SRCDIR) COPYING.libxml2
-WINPTHREADS_DIST := mingw-w64-v$(WINPTHREADS_VERSION).tar.bz2
-WINPTHREADS_SRCDIR := winpthreads-$(WINPTHREADS_VERSION)
-SRCDIR_TARGETS += $(WINPTHREADS_SRCDIR)
-DIST_TARGETS += $(WINPTHREADS_DIST)
-$(WINPTHREADS_DIST):
- wget $(WINPTHREADS_URL)
-$(WINPTHREADS_SRCDIR):$(WINPTHREADS_DIST) checksums_verified
- tar xvf $<
- cp -aT mingw-w64-v$(WINPTHREADS_VERSION)/mingw-w64-libraries/winpthreads $@
- cp $@/COPYING COPYING.winpthreads
-MAKE_CLEAN_FILES += $(WINPTHREADS_SRCDIR) mingw-w64-v$(WINPTHREADS_VERSION) COPYING.winpthreads
-
checksums_verified:$(DIST_TARGETS)
sha256sum -c sha256sums
MAKE_CLEAN_FILES += build_libxml_$(1)
endef
-#
-# declare_winpthreads_target(arch)
-#
-define declare_winpthreads_target
-winpthreads_$(1):$(WINPTHREADS_SRCDIR)
- builddir=build_winpthreads_$(1); \
- rm -rf $$$$builddir; \
- cp -r $(WINPTHREADS_SRCDIR) $$$$builddir; \
- cd $$$$builddir; \
- ./configure \
- --host=$(1)-w64-mingw32 \
- --enable-static \
- --disable-shared \
- --prefix=$$$$PWD/../sysroot_$(1) \
- CFLAGS=-O2; \
- $(MAKE) install; \
- sed -i -e 's/if defined DLL_EXPORT/if 0/' \
- ../sysroot_$(1)/include/pthread.h;
-
-$(1)_BUILD_TARGETS += winpthreads_$(1)
-MAKE_CLEAN_FILES += build_winpthreads_$(1)
-endef
-
#
# declare_arch_targets(arch)
#
define declare_arch_targets
$(eval $(call declare_libxml_target,$(1)))
-$(eval $(call declare_winpthreads_target,$(1)))
sysroot_$(1): $($(1)_BUILD_TARGETS)
5d2cc3d78bec3dbe212a9d7fa629ada25a7da928af432c93060ff5c17ee28a9c libxml2-2.10.3.tar.xz
-ba6b430aed72c63a3768531f6a3ffc2b0fde2c57a3b251450dcf489a894f0894 mingw-w64-v10.0.0.tar.bz2