+ return TRUE;
+}
+
+/*
+ * Test lock and write_and_unlock
+ */
+static gboolean
+inc_counter(file_lock *lock)
+{
+ char old_val = 'a';
+ char new_val;
+
+ if (lock->len) {
+ old_val = lock->data[0];
+ }
+
+ g_assert(old_val < 'z');
+
+ new_val = old_val + 1;
+ if (file_lock_write(lock, &new_val, 1) == -1) {
+ g_fprintf(stderr, "file_lock_write: %s\n",
+ strerror(errno));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+#define pipeget(fd, cp) \
+ (read((fd), (cp), 1) == 1)
+
+#define pipeput(fd, s) \
+ g_assert(write((fd), s, 1) == 1);
+
+static void
+locking_slave(int in_fd, int out_fd)
+{
+ char cmd;
+ int rv;
+ file_lock *lock = file_lock_new(TEST_FILENAME);
+ gboolean locked = 0;
+
+ while (1) {
+ if (!pipeget(in_fd, &cmd))
+ cmd = 'q';
+
+ switch (cmd) {
+ case 'q': /* q = quit */
+ tu_dbg("slave: quitting\n");
+ file_lock_free(lock);
+ lock = NULL;
+ return;
+
+ case 'l': /* l = try locking; reply with 'y' or 'n' */
+ g_assert(!locked);
+ rv = file_lock_lock(lock);
+ if (rv == -1) {
+ g_fprintf(stderr, "file_lock_lock: %s\n",
+ strerror(errno));
+ return;
+ }
+ tu_dbg("slave: lock attempt => %s\n", (rv == 1)? "n" : "y");
+ pipeput(out_fd, (rv == 1)? "n" : "y");
+ if (rv != 1)
+ locked = 1;
+ break;
+
+ case 'i': /* i = increment counter, reply with new value */
+ g_assert(locked);
+ if (!inc_counter(lock))
+ return;
+ tu_dbg("slave: inc'd to %c\n", lock->data[0]);
+ pipeput(out_fd, lock->data);
+ break;
+
+ case 'u': /* u = try unlocking; reply with 'k' */
+ g_assert(locked);
+ rv = file_lock_unlock(lock);
+ if (rv != 0) {
+ g_fprintf(stderr, "file_lock_unlock: %s\n",
+ strerror(errno));
+ return;
+ }
+ tu_dbg("slave: unlocked\n");
+ pipeput(out_fd, "k");
+ locked = 0;
+ break;
+
+ default:
+ return;
+ }
+ }
+}
+
+static int
+locking_master(int in_fd, int out_fd)
+{
+ file_lock *lock = file_lock_new(TEST_FILENAME);
+ int rv;
+ char slaveres;
+
+ /* start by locking here and incrementing the value */
+ rv = file_lock_lock(lock);
+ if (rv == -1) {
+ g_fprintf(stderr, "file_lock_lock: %s\n", strerror(errno));
+ return 0;
+ }
+ g_assert(rv != 1); /* not already locked */
+ tu_dbg("master: locked\n");
+
+ if (!inc_counter(lock))
+ return 0;
+
+ g_assert(lock->data[0] == 'b');
+ tu_dbg("master: inc'd to b\n");
+
+ /* unlock and re-lock */
+ rv = file_lock_unlock(lock);
+ if (rv != 0) {
+ g_fprintf(stderr, "file_lock_unlock: %s\n", strerror(errno));
+ return 0;
+ }
+ tu_dbg("master: unlocked\n");
+
+ rv = file_lock_lock(lock);
+ if (rv == -1) {
+ g_fprintf(stderr, "file_lock_lock: %s\n", strerror(errno));
+ return 0;
+ }
+ g_assert(rv != 1); /* not already locked */
+ tu_dbg("master: locked\n");
+
+ /* inc it again */
+ g_assert(lock->data[0] == 'b');
+ inc_counter(lock);
+ g_assert(lock->data[0] == 'c');
+ tu_dbg("master: inc'd to c\n");
+
+ /* the slave should fail to get a lock now */
+ pipeput(out_fd, "l");
+ g_assert(pipeget(in_fd, &slaveres));
+ g_assert(slaveres == 'n');
+
+ /* and, finally unlock */
+ rv = file_lock_unlock(lock);
+ if (rv != 0) {
+ g_fprintf(stderr, "file_lock_unlock: %s\n", strerror(errno));
+ return 0;
+ }
+ tu_dbg("master: unlocked\n");
+
+ /* the slave should succeed now */
+ pipeput(out_fd, "l");
+ g_assert(pipeget(in_fd, &slaveres));
+ g_assert(slaveres == 'y');
+
+ pipeput(out_fd, "i");
+ g_assert(pipeget(in_fd, &slaveres));
+ g_assert(slaveres == 'd');
+
+ /* master shouldn't be able to lock now */
+ rv = file_lock_lock(lock);
+ if (rv == -1) {
+ g_fprintf(stderr, "file_lock_lock: %s\n", strerror(errno));
+ return 0;
+ }
+ g_assert(rv == 1); /* already locked */
+ tu_dbg("master: lock attempt failed (as expected)\n");
+
+ pipeput(out_fd, "i");
+ g_assert(pipeget(in_fd, &slaveres));
+ g_assert(slaveres == 'e');
+
+ /* get the slave to unlock */
+ pipeput(out_fd, "u");
+ g_assert(pipeget(in_fd, &slaveres));
+ g_assert(slaveres == 'k');
+
+ /* we should get a lock now */
+ rv = file_lock_lock(lock);
+ if (rv == -1) {
+ g_fprintf(stderr, "file_lock_lock: %s\n", strerror(errno));
+ return 0;
+ }
+ g_assert(rv != 1); /* not already locked */
+ tu_dbg("master: lock attempt succeeded\n");
+
+ g_assert(lock->data[0] == 'e');
+
+ /* leave it unlocked, just to see what happens */
+