X-Git-Url: https://wimlib.net/git/?p=wimlib;a=blobdiff_plain;f=src%2Fwrite.c;h=5b586ceea23f8795cff7c28623ce2ff573df59a1;hp=a08bc8503a6c5a57f908ab7f535787205fe3fded;hb=277957c10e96a23f822b2e6ae22c8d126a93141a;hpb=9b9a502863318d6208da2818b1d522346e5eee9e diff --git a/src/write.c b/src/write.c index a08bc850..5b586cee 100644 --- a/src/write.c +++ b/src/write.c @@ -25,6 +25,15 @@ * along with wimlib; if not, see http://www.gnu.org/licenses/. */ +#include "config.h" + +#if defined(HAVE_SYS_FILE_H) && defined(HAVE_FLOCK) +/* On BSD, this should be included before "list.h" so that "list.h" can + * overwrite the LIST_HEAD macro. */ +#include +#endif + +#include "list.h" #include "wimlib_internal.h" #include "io.h" #include "dentry.h" @@ -32,14 +41,14 @@ #include "xml.h" #include "lzx.h" #include "xpress.h" -#include #ifdef ENABLE_MULTITHREADED_COMPRESSION -#include #include -#include #endif +#include +#include + #ifdef WITH_NTFS_3G #include #include @@ -47,13 +56,13 @@ #include #endif - #ifdef HAVE_ALLOCA_H #include #else #include #endif + static int do_fflush(FILE *fp) { int ret = fflush(fp); @@ -537,13 +546,14 @@ out: #ifdef ENABLE_MULTITHREADED_COMPRESSION struct shared_queue { - sem_t filled_slots; - sem_t empty_slots; - pthread_mutex_t lock; + unsigned size; unsigned front; unsigned back; + unsigned filled_slots; void **array; - unsigned size; + pthread_mutex_t lock; + pthread_cond_t msg_avail_cond; + pthread_cond_t space_avail_cond; }; static int shared_queue_init(struct shared_queue *q, unsigned size) @@ -551,46 +561,52 @@ static int shared_queue_init(struct shared_queue *q, unsigned size) q->array = CALLOC(sizeof(q->array[0]), size); if (!q->array) return WIMLIB_ERR_NOMEM; - - sem_init(&q->filled_slots, 0, 0); - sem_init(&q->empty_slots, 0, size); - pthread_mutex_init(&q->lock, NULL); + q->filled_slots = 0; q->front = 0; q->back = size - 1; q->size = size; + pthread_mutex_init(&q->lock, NULL); + pthread_cond_init(&q->msg_avail_cond, NULL); + pthread_cond_init(&q->space_avail_cond, NULL); return 0; } static void shared_queue_destroy(struct shared_queue *q) { - sem_destroy(&q->filled_slots); - sem_destroy(&q->empty_slots); - pthread_mutex_destroy(&q->lock); FREE(q->array); + pthread_mutex_destroy(&q->lock); + pthread_cond_destroy(&q->msg_avail_cond); + pthread_cond_destroy(&q->space_avail_cond); } static void shared_queue_put(struct shared_queue *q, void *obj) { - sem_wait(&q->empty_slots); pthread_mutex_lock(&q->lock); + while (q->filled_slots == q->size) + pthread_cond_wait(&q->space_avail_cond, &q->lock); q->back = (q->back + 1) % q->size; q->array[q->back] = obj; + q->filled_slots++; - sem_post(&q->filled_slots); + pthread_cond_broadcast(&q->msg_avail_cond); pthread_mutex_unlock(&q->lock); } static void *shared_queue_get(struct shared_queue *q) { - sem_wait(&q->filled_slots); + void *obj; + pthread_mutex_lock(&q->lock); + while (q->filled_slots == 0) + pthread_cond_wait(&q->msg_avail_cond, &q->lock); - void *obj = q->array[q->front]; + obj = q->array[q->front]; q->array[q->front] = NULL; q->front = (q->front + 1) % q->size; + q->filled_slots--; - sem_post(&q->empty_slots); + pthread_cond_broadcast(&q->space_avail_cond); pthread_mutex_unlock(&q->lock); return obj; } @@ -1486,6 +1502,61 @@ out: return ret; } +#if defined(HAVE_SYS_FILE_H) && defined(HAVE_FLOCK) +int lock_wim(FILE *fp, const char *path) +{ + int ret = 0; + if (fp) { + ret = flock(fileno(fp), LOCK_EX | LOCK_NB); + if (ret != 0) { + if (errno == EWOULDBLOCK) { + ERROR("`%s' is already being modified or has been " + "mounted read-write\n" + " by another process!", path); + ret = WIMLIB_ERR_ALREADY_LOCKED; + } else { + WARNING("Failed to lock `%s': %s", + path, strerror(errno)); + ret = 0; + } + } + } + return ret; +} +#endif + +static int open_wim_writable(WIMStruct *w, const char *path, + bool trunc, bool readable) +{ + const char *mode; + int ret = 0; + if (trunc) + if (readable) + mode = "w+b"; + else + mode = "wb"; + else + mode = "r+b"; + + DEBUG("Opening `%s' read-write", path); + wimlib_assert(w->out_fp == NULL); + wimlib_assert(path != NULL); + w->out_fp = fopen(path, mode); + if (!w->out_fp) { + ERROR_WITH_ERRNO("Failed to open `%s' for writing", path); + return WIMLIB_ERR_OPEN; + } + if (trunc) { + ret = lock_wim(w->out_fp, path); + if (ret != 0) { + fclose(w->out_fp); + w->out_fp = NULL; + } + } + return ret; +} + + static void close_wim_writable(WIMStruct *w) { if (w->out_fp) {