Add debugging information to yarn error messages.
diff --git a/pigz.c b/pigz.c
index 0667360..b5f6ea8 100644
--- a/pigz.c
+++ b/pigz.c
@@ -4280,7 +4280,7 @@
 #ifndef NOTHREAD
 // handle error received from yarn function
 local void cut_yarn(int err) {
-    throw(err, err == ENOMEM ? "not enough memory" : "internal threads error");
+    throw(err, "internal threads error");
 }
 #endif
 
diff --git a/yarn.c b/yarn.c
index d1debac..9a4f975 100644
--- a/yarn.c
+++ b/yarn.c
@@ -1,6 +1,6 @@
 /* yarn.c -- generic thread operations implemented using pthread functions
- * Copyright (C) 2008, 2011, 2012, 2015, 2018 Mark Adler
- * Version 1.5  8 May 2018  Mark Adler
+ * Copyright (C) 2008, 2011, 2012, 2015, 2018, 2019 Mark Adler
+ * Version 1.6  3 Apr 2019  Mark Adler
  * For conditions of distribution and use, see copyright notice in yarn.h
  */
 
@@ -21,6 +21,7 @@
                        Accept and do nothing for NULL argument to free_lock()
    1.5     8 May 2018  Remove destruct() to avoid use of pthread_cancel()
                        Normalize the code style
+   1.6     3 Apr 2019  Add debugging information to fail() error messages.
  */
 
 // For thread portability.
@@ -42,7 +43,7 @@
     // pthread_mutex_lock(), pthread_mutex_unlock(), pthread_mutex_destroy(),
     // pthread_cond_t, PTHREAD_COND_INITIALIZER, pthread_cond_init(),
     // pthread_cond_broadcast(), pthread_cond_wait(), pthread_cond_destroy()
-#include <errno.h>      // ENOMEM, EAGAIN, EINVAL
+#include <errno.h>      // EPERM, ESRCH, EDEADLK, ENOMEM, EBUSY, EINVAL, EAGAIN
 
 // Interface definition.
 #include "yarn.h"
@@ -56,12 +57,37 @@
 
 
 // Immediately exit -- use for errors that shouldn't ever happen.
-local void fail(int err) {
+local void fail(int err, char const *file, long line, char const *func) {
+    fprintf(stderr, "%s: ", yarn_prefix);
+    switch (err) {
+        case EPERM:
+            fputs("already unlocked", stderr);
+            break;
+        case ESRCH:
+            fputs("no such thread", stderr);
+            break;
+        case EDEADLK:
+            fputs("resource deadlock", stderr);
+            break;
+        case ENOMEM:
+            fputs("out of memory", stderr);
+            break;
+        case EBUSY:
+            fputs("can't destroy locked resource", stderr);
+            break;
+        case EINVAL:
+            fputs("invalid request", stderr);
+            break;
+        case EAGAIN:
+            fputs("resource unavailable", stderr);
+            break;
+        default:
+            fprintf(stderr, "internal error %d", err);
+    }
+    fprintf(stderr, " (%s:%ld:%s).\n", file, line, func);
     if (yarn_abort != NULL)
         yarn_abort(err);
-    fprintf(stderr, "%s: %s (%d) -- aborting\n", yarn_prefix,
-            err == ENOMEM ? "out of memory" : "internal pthread error", err);
-    exit(err == ENOMEM || err == EAGAIN ? err : EINVAL);
+    exit(err);
 }
 
 // Memory handling routines provided by user. If none are provided, malloc()
@@ -78,11 +104,11 @@
 }
 
 // Memory allocation that cannot fail (from the point of view of the caller).
-local void *my_malloc(size_t size) {
+local void *my_malloc(size_t size, char const *file, long line) {
     void *block;
 
     if ((block = my_malloc_f(size)) == NULL)
-        fail(ENOMEM);
+        fail(ENOMEM, file, line, "malloc");
     return block;
 }
 
@@ -94,69 +120,76 @@
     long value;
 };
 
-lock *new_lock(long initial) {
-    int ret;
-    lock *bolt;
-
-    bolt = my_malloc(sizeof(struct lock_s));
-    if ((ret = pthread_mutex_init(&(bolt->mutex), NULL)) ||
-        (ret = pthread_cond_init(&(bolt->cond), NULL)))
-        fail(ret);
+lock *new_lock_(long initial, char const *file, long line) {
+    lock *bolt = my_malloc(sizeof(struct lock_s), file, line);
+    int ret = pthread_mutex_init(&(bolt->mutex), NULL);
+    if (ret)
+        fail(ret, file, line, "mutex_init");
+    ret = pthread_cond_init(&(bolt->cond), NULL);
+    if (ret)
+        fail(ret, file, line, "cond_init");
     bolt->value = initial;
     return bolt;
 }
 
-void possess(lock *bolt) {
-    int ret;
-
-    if ((ret = pthread_mutex_lock(&(bolt->mutex))) != 0)
-        fail(ret);
+void possess_(lock *bolt, char const *file, long line) {
+    int ret = pthread_mutex_lock(&(bolt->mutex));
+    if (ret)
+        fail(ret, file, line, "mutex_lock");
 }
 
-void release(lock *bolt) {
-    int ret;
-
-    if ((ret = pthread_mutex_unlock(&(bolt->mutex))) != 0)
-        fail(ret);
+void release_(lock *bolt, char const *file, long line) {
+    int ret = pthread_mutex_unlock(&(bolt->mutex));
+    if (ret)
+        fail(ret, file, line, "mutex_unlock");
 }
 
-void twist(lock *bolt, enum twist_op op, long val) {
-    int ret;
-
+void twist_(lock *bolt, enum twist_op op, long val,
+            char const *file, long line) {
     if (op == TO)
         bolt->value = val;
     else if (op == BY)
         bolt->value += val;
-    if ((ret = pthread_cond_broadcast(&(bolt->cond))) ||
-        (ret = pthread_mutex_unlock(&(bolt->mutex))))
-        fail(ret);
+    int ret = pthread_cond_broadcast(&(bolt->cond));
+    if (ret)
+        fail(ret, file, line, "cond_broadcast");
+    ret = pthread_mutex_unlock(&(bolt->mutex));
+    if (ret)
+        fail(ret, file, line, "mutex_unlock");
 }
 
 #define until(a) while(!(a))
 
-void wait_for(lock *bolt, enum wait_op op, long val) {
-    int ret;
-
+void wait_for_(lock *bolt, enum wait_op op, long val,
+               char const *file, long line) {
     switch (op) {
-    case TO_BE:
-        until (bolt->value == val)
-            if ((ret = pthread_cond_wait(&(bolt->cond), &(bolt->mutex))) != 0)
-                fail(ret);
-        break;
-    case NOT_TO_BE:
-        until (bolt->value != val)
-            if ((ret = pthread_cond_wait(&(bolt->cond), &(bolt->mutex))) != 0)
-                fail(ret);
-        break;
-    case TO_BE_MORE_THAN:
-        until (bolt->value > val)
-            if ((ret = pthread_cond_wait(&(bolt->cond), &(bolt->mutex))) != 0)
-                fail(ret);
-        break;
-    case TO_BE_LESS_THAN:
-        until (bolt->value < val)
-            if ((ret = pthread_cond_wait(&(bolt->cond), &(bolt->mutex))) != 0)
-                fail(ret);
+        case TO_BE:
+            until (bolt->value == val) {
+                int ret = pthread_cond_wait(&(bolt->cond), &(bolt->mutex));
+                if (ret)
+                    fail(ret, file, line, "cond_wait");
+            }
+            break;
+        case NOT_TO_BE:
+            until (bolt->value != val) {
+                int ret = pthread_cond_wait(&(bolt->cond), &(bolt->mutex));
+                if (ret)
+                    fail(ret, file, line, "cond_wait");
+            }
+            break;
+        case TO_BE_MORE_THAN:
+            until (bolt->value > val) {
+                int ret = pthread_cond_wait(&(bolt->cond), &(bolt->mutex));
+                if (ret)
+                    fail(ret, file, line, "cond_wait");
+            }
+            break;
+        case TO_BE_LESS_THAN:
+            until (bolt->value < val) {
+                int ret = pthread_cond_wait(&(bolt->cond), &(bolt->mutex));
+                if (ret)
+                    fail(ret, file, line, "cond_wait");
+            }
     }
 }
 
@@ -164,14 +197,15 @@
     return bolt->value;
 }
 
-void free_lock(lock *bolt) {
-    int ret;
-
+void free_lock_(lock *bolt, char const *file, long line) {
     if (bolt == NULL)
         return;
-    if ((ret = pthread_cond_destroy(&(bolt->cond))) ||
-        (ret = pthread_mutex_destroy(&(bolt->mutex))))
-        fail(ret);
+    int ret = pthread_cond_destroy(&(bolt->cond));
+    if (ret)
+        fail(ret, file, line, "cond_destroy");
+    ret = pthread_mutex_destroy(&(bolt->mutex));
+    if (ret)
+        fail(ret, file, line, "mutex_destroy");
     my_free(bolt);
 }
 
@@ -196,26 +230,26 @@
 struct capsule {
     void (*probe)(void *);
     void *payload;
+    char const *file;
+    long line;
 };
 
 // Mark the calling thread as done and alert join_all().
-local void reenter(void *dummy) {
-    thread *match, **prior;
-    pthread_t me;
-
-    (void)dummy;
+local void reenter(void *arg) {
+    struct capsule *capsule = arg;
 
     // find this thread in the threads list by matching the thread id
-    me = pthread_self();
-    possess(&(threads_lock));
-    prior = &(threads);
+    pthread_t me = pthread_self();
+    possess_(&(threads_lock), capsule->file, capsule->line);
+    thread **prior = &(threads);
+    thread *match;
     while ((match = *prior) != NULL) {
         if (pthread_equal(match->id, me))
             break;
         prior = &(match->next);
     }
     if (match == NULL)
-        fail(EINVAL);
+        fail(ESRCH, capsule->file, capsule->line, "reenter lost");
 
     // mark this thread as done and move it to the head of the list
     match->done = 1;
@@ -226,7 +260,7 @@
     }
 
     // update the count of threads to be joined and alert join_all()
-    twist(&(threads_lock), BY, +1);
+    twist_(&(threads_lock), BY, +1, capsule->file, capsule->line);
 }
 
 // All threads go through this routine. Just before a thread exits, it marks
@@ -237,7 +271,7 @@
     struct capsule *capsule = arg;
 
     // run reenter() before leaving
-    pthread_cleanup_push(reenter, NULL);
+    pthread_cleanup_push(reenter, arg);
 
     // execute the requested function with argument
     capsule->probe(capsule->payload);
@@ -252,64 +286,69 @@
 
 // Not all POSIX implementations create threads as joinable by default, so that
 // is made explicit here.
-thread *launch(void (*probe)(void *), void *payload) {
-    int ret;
-    thread *th;
-    struct capsule *capsule;
-    pthread_attr_t attr;
-
+thread *launch_(void (*probe)(void *), void *payload,
+                char const *file, long line) {
     // construct the requested call and argument for the ignition() routine
     // (allocated instead of automatic so that we're sure this will still be
     // there when ignition() actually starts up -- ignition() will free this
     // allocation)
-    capsule = my_malloc(sizeof(struct capsule));
+    struct capsule *capsule = my_malloc(sizeof(struct capsule), file, line);
     capsule->probe = probe;
     capsule->payload = payload;
+    capsule->file = file;
+    capsule->line = line;
 
     // assure this thread is in the list before join_all() or ignition() looks
     // for it
-    possess(&(threads_lock));
+    possess_(&(threads_lock), file, line);
 
     // create the thread and call ignition() from that thread
-    th = my_malloc(sizeof(struct thread_s));
-    if ((ret = pthread_attr_init(&attr)) ||
-        (ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE)) ||
-        (ret = pthread_create(&(th->id), &attr, ignition, capsule)) ||
-        (ret = pthread_attr_destroy(&attr)))
-        fail(ret);
+    thread *th = my_malloc(sizeof(struct thread_s), file, line);
+    pthread_attr_t attr;
+    int ret = pthread_attr_init(&attr);
+    if (ret)
+        fail(ret, file, line, "attr_init");
+    ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+    if (ret)
+        fail(ret, file, line, "attr_setdetachstate");
+    ret = pthread_create(&(th->id), &attr, ignition, capsule);
+    if (ret)
+        fail(ret, file, line, "create");
+    ret = pthread_attr_destroy(&attr);
+    if (ret)
+        fail(ret, file, line, "attr_destroy");
 
     // put the thread in the threads list for join_all()
     th->done = 0;
     th->next = threads;
     threads = th;
-    release(&(threads_lock));
+    release_(&(threads_lock), file, line);
     return th;
 }
 
-void join(thread *ally) {
-    int ret;
-    thread *match, **prior;
-
+void join_(thread *ally, char const *file, long line) {
     // wait for thread to exit and return its resources
-    if ((ret = pthread_join(ally->id, NULL)) != 0)
-        fail(ret);
+    int ret = pthread_join(ally->id, NULL);
+    if (ret)
+        fail(ret, file, line, "join");
 
     // find the thread in the threads list
-    possess(&(threads_lock));
-    prior = &(threads);
+    possess_(&(threads_lock), file, line);
+    thread **prior = &(threads);
+    thread *match;
     while ((match = *prior) != NULL) {
         if (match == ally)
             break;
         prior = &(match->next);
     }
     if (match == NULL)
-        fail(EINVAL);
+        fail(ESRCH, file, line, "join lost");
 
     // remove thread from list and update exited count, free thread
     if (match->done)
         threads_lock.value--;
     *prior = match->next;
-    release(&(threads_lock));
+    release_(&(threads_lock), file, line);
     my_free(ally);
 }
 
@@ -317,33 +356,32 @@
 // announced that they have exited (see ignition()). When there are many
 // threads, this is faster than waiting for some random thread to exit while a
 // bunch of other threads have already exited.
-int join_all(void) {
-    int ret, count;
-    thread *match, **prior;
-
+int join_all_(char const *file, long line) {
     // grab the threads list and initialize the joined count
-    count = 0;
-    possess(&(threads_lock));
+    int count = 0;
+    possess_(&(threads_lock), file, line);
 
     // do until threads list is empty
     while (threads != NULL) {
         // wait until at least one thread has reentered
-        wait_for(&(threads_lock), NOT_TO_BE, 0);
+        wait_for_(&(threads_lock), NOT_TO_BE, 0, file, line);
 
         // find the first thread marked done (should be at or near the top)
-        prior = &(threads);
+        thread **prior = &(threads);
+        thread *match;
         while ((match = *prior) != NULL) {
             if (match->done)
                 break;
             prior = &(match->next);
         }
         if (match == NULL)
-            fail(EINVAL);
+            fail(ESRCH, file, line, "join_all lost");
 
         // join the thread (will be almost immediate), remove from the threads
         // list, update the reenter count, and free the thread
-        if ((ret = pthread_join(match->id, NULL)) != 0)
-            fail(ret);
+        int ret = pthread_join(match->id, NULL);
+        if (ret)
+            fail(ret, file, line, "join");
         threads_lock.value--;
         *prior = match->next;
         my_free(match);
@@ -351,6 +389,6 @@
     }
 
     // let go of the threads list and return the number of threads joined
-    release(&(threads_lock));
+    release_(&(threads_lock), file, line);
     return count;
 }
diff --git a/yarn.h b/yarn.h
index b19a59f..1076d73 100644
--- a/yarn.h
+++ b/yarn.h
@@ -111,19 +111,28 @@
 void yarn_mem(void *(*)(size_t), void (*)(void *));
 
 typedef struct thread_s thread;
-thread *launch(void (*)(void *), void *);
-void join(thread *);
-int join_all(void);
+thread *launch_(void (*)(void *), void *, char const *, long);
+#define launch(a, b) launch_(a, b, __FILE__, __LINE__)
+void join_(thread *, char const *, long);
+#define join(a) join_(a, __FILE__, __LINE__)
+int join_all_(char const *, long);
+#define join_all() join_all_(__FILE__, __LINE__)
 
 typedef struct lock_s lock;
-lock *new_lock(long);
-void possess(lock *);
-void release(lock *);
+lock *new_lock_(long, char const *, long);
+#define new_lock(a) new_lock_(a, __FILE__, __LINE__)
+void possess_(lock *, char const *, long);
+#define possess(a) possess_(a, __FILE__, __LINE__)
+void release_(lock *, char const *, long);
+#define release(a) release_(a, __FILE__, __LINE__)
 enum twist_op { TO, BY };
-void twist(lock *, enum twist_op, long);
+void twist_(lock *, enum twist_op, long, char const *, long);
+#define twist(a, b, c) twist_(a, b, c, __FILE__, __LINE__)
 enum wait_op {
     TO_BE, /* or */ NOT_TO_BE, /* that is the question */
     TO_BE_MORE_THAN, TO_BE_LESS_THAN };
-void wait_for(lock *, enum wait_op, long);
+void wait_for_(lock *, enum wait_op, long, char const *, long);
+#define wait_for(a, b, c) wait_for_(a, b, c, __FILE__, __LINE__)
 long peek_lock(lock *);
-void free_lock(lock *);
+void free_lock_(lock *, char const *, long);
+#define free_lock(a) free_lock_(a, __FILE__, __LINE__)