made RawQueue options type-safe
diff --git a/aos/linux_code/ipc_lib/ipc_lib.gyp b/aos/linux_code/ipc_lib/ipc_lib.gyp
index edca758..35091e5 100644
--- a/aos/linux_code/ipc_lib/ipc_lib.gyp
+++ b/aos/linux_code/ipc_lib/ipc_lib.gyp
@@ -50,6 +50,9 @@
         'core_lib',
         '<(AOS)/build/aos.gyp:logging_interface',
       ],
+      'export_dependent_settings': [
+        '<(AOS)/build/aos.gyp:logging_interface',
+      ],
     },
     {
       'target_name': 'raw_queue_test',
@@ -66,6 +69,7 @@
         '<(AOS)/common/common.gyp:time',
         '<(AOS)/common/common.gyp:die',
         '<(AOS)/common/util/util.gyp:thread',
+        '<(AOS)/common/util/util.gyp:death_test_log_implementation',
       ],
     },
     {
diff --git a/aos/linux_code/ipc_lib/queue.cc b/aos/linux_code/ipc_lib/queue.cc
index a3ec15a..e8e81dc 100644
--- a/aos/linux_code/ipc_lib/queue.cc
+++ b/aos/linux_code/ipc_lib/queue.cc
@@ -12,7 +12,6 @@
 #include <memory>
 #include <algorithm>
 
-#include "aos/common/logging/logging.h"
 #include "aos/common/type_traits.h"
 #include "aos/linux_code/ipc_lib/core_lib.h"
 
@@ -35,11 +34,11 @@
 
 }  // namespace
 
-const int RawQueue::kPeek;
-const int RawQueue::kFromEnd;
-const int RawQueue::kNonBlock;
-const int RawQueue::kBlock;
-const int RawQueue::kOverride;
+constexpr Options<RawQueue>::Option RawQueue::kPeek;
+constexpr Options<RawQueue>::Option RawQueue::kFromEnd;
+constexpr Options<RawQueue>::Option RawQueue::kNonBlock;
+constexpr Options<RawQueue>::Option RawQueue::kBlock;
+constexpr Options<RawQueue>::Option RawQueue::kOverride;
 
 // This is what gets stuck in before each queue message in memory. It is always
 // allocated aligned to 8 bytes and its size has to maintain that alignment for
@@ -297,9 +296,9 @@
   return r;
 }
 
-bool RawQueue::WriteMessage(void *msg, int options) {
+bool RawQueue::DoWriteMessage(void *msg, Options<RawQueue> options) {
   if (kWriteDebug) {
-    printf("queue: %p->WriteMessage(%p, %x)\n", this, msg, options);
+    printf("queue: %p->WriteMessage(%p, %x)\n", this, msg, options.printable());
   }
   {
     MutexLocker locker(&data_lock_);
@@ -324,6 +323,7 @@
         DecrementMessageReferenceCount(data_[data_start_]);
         data_start_ = index_add1(data_start_);
       } else {  // kBlock
+        assert(options & kBlock);
         if (kWriteDebug) {
           printf("queue: going to wait for writable_ of %p\n", this);
         }
@@ -370,7 +370,7 @@
   }
 }
 
-bool RawQueue::ReadCommonStart(int options, int *index) {
+bool RawQueue::ReadCommonStart(Options<RawQueue> options, int *index) {
   while (data_start_ == data_end_ || ((index != NULL) && messages_ <= *index)) {
     if (options & kNonBlock) {
       if (kReadDebug) {
@@ -378,6 +378,7 @@
       }
       return false;
     } else {  // kBlock
+      assert(options & kBlock);
       if (kReadDebug) {
         printf("queue: going to wait for readable_ of %p\n", this);
       }
@@ -407,10 +408,10 @@
   return pos;
 }
 
-const void *RawQueue::ReadMessage(int options) {
+const void *RawQueue::DoReadMessage(Options<RawQueue> options) {
   // TODO(brians): Test this function.
   if (kReadDebug) {
-    printf("queue: %p->ReadMessage(%x)\n", this, options);
+    printf("queue: %p->ReadMessage(%x)\n", this, options.printable());
   }
   void *msg = NULL;
 
@@ -468,10 +469,11 @@
   return msg;
 }
 
-const void *RawQueue::ReadMessageIndex(int options, int *index) {
+const void *RawQueue::DoReadMessageIndex(Options<RawQueue> options,
+                                         int *index) {
   if (kReadDebug) {
     printf("queue: %p->ReadMessageIndex(%x, %p(*=%d))\n",
-           this, options, index, *index);
+           this, options.printable(), index, *index);
   }
   void *msg = NULL;
 
@@ -491,7 +493,10 @@
       printf("queue: %p reading from c1: %d\n", this, LastMessageIndex());
     }
     msg = data_[LastMessageIndex()];
-    if (!(options & kPeek)) *index = messages_;
+
+    // We'd skip this if we had kPeek, but kPeek | kFromEnd isn't valid for
+    // reading with an index.
+    *index = messages_;
   } else {
     // Where we're going to start reading.
     int my_start;
diff --git a/aos/linux_code/ipc_lib/queue.h b/aos/linux_code/ipc_lib/queue.h
index 5edce62..31e8075 100644
--- a/aos/linux_code/ipc_lib/queue.h
+++ b/aos/linux_code/ipc_lib/queue.h
@@ -6,6 +6,8 @@
 #include "aos/linux_code/ipc_lib/shared_mem.h"
 #include "aos/common/mutex.h"
 #include "aos/common/condition.h"
+#include "aos/common/util/options.h"
+#include "aos/common/logging/logging.h"
 
 // TODO(brians) add valgrind client requests to the queue and shared_mem_malloc
 // code to make checking for leaks work better
@@ -56,38 +58,45 @@
                       int recycle_hash, int recycle_queue_length,
                       RawQueue **recycle);
 
-  // Constants for passing to options arguments.
-  // The non-conflicting ones can be combined with bitwise-or.
-
   // Doesn't update the currently read index (the read messages in the queue or
   // the index). This means the returned message (and any others skipped with
   // kFromEnd) will be left in the queue.
   // For reading only.
-  static const int kPeek = 0x0001;
+  // Not valid for ReadMessageIndex combined with kFromEnd.
+  static constexpr Options<RawQueue>::Option kPeek{0x0001};
   // Reads the last message in the queue instead of just the next one.
   // NOTE: This removes all of the messages until the last one from the queue
   // (which means that nobody else will read them).
   // For reading only.
-  static const int kFromEnd = 0x0002;
+  // Not valid for ReadMessageIndex combined with kPeek.
+  static constexpr Options<RawQueue>::Option kFromEnd{0x0002};
   // Causes reads to return NULL and writes to fail instead of waiting.
   // For reading and writing.
-  static const int kNonBlock = 0x0004;
+  static constexpr Options<RawQueue>::Option kNonBlock{0x0004};
   // Causes things to block.
-  // IMPORTANT: Has a value of 0 so that it is the default. This has to stay
-  // this way.
   // For reading and writing.
-  static const int kBlock = 0x0000;
+  static constexpr Options<RawQueue>::Option kBlock{0x0008};
   // Causes writes to overwrite the oldest message in the queue instead of
   // blocking.
   // For writing only.
-  static const int kOverride = 0x0008;
+  static constexpr Options<RawQueue>::Option kOverride{0x0010};
 
   // Writes a message into the queue.
   // This function takes ownership of msg.
   // NOTE: msg must point to a valid message from this queue
   // Returns true on success. A return value of false means msg has already been
   // freed.
-  bool WriteMessage(void *msg, int options);
+  bool WriteMessage(void *msg, Options<RawQueue> options) {
+    static constexpr Options<RawQueue> kWriteFailureOptions =
+        kNonBlock | kBlock | kOverride;
+    if (!options.NoOthersSet(kWriteFailureOptions)) {
+      LOG(FATAL, "illegal write options in %x\n", options.printable());
+    }
+    if (!options.ExactlyOneSet(kWriteFailureOptions)) {
+      LOG(FATAL, "invalid write options %x\n", options.printable());
+    }
+    return DoWriteMessage(msg, options);
+  }
 
   // Reads a message out of the queue.
   // The return value will have at least the length of this queue's worth of
@@ -96,13 +105,26 @@
   // messsage. Do not cast the const away!
   // IMPORTANT: The return value (if not NULL) must eventually be passed to
   // FreeMessage.
-  const void *ReadMessage(int options);
+  const void *ReadMessage(Options<RawQueue> options) {
+    CheckReadOptions(options);
+    return DoReadMessage(options);
+  }
   // The same as ReadMessage, except it will never return the
   // same message twice (when used with the same index argument). However,
   // may not return some messages that pass through the queue.
   // *index should start as 0. index does not have to be in shared memory, but
   // it can be.
-  const void *ReadMessageIndex(int options, int *index);
+  // Calling with both kPeek and kFromEnd in options isn't valid because that
+  // would mean ignoring index, which would make this function the same as
+  // ReadMessage (which should be used instead).
+  const void *ReadMessageIndex(Options<RawQueue> options, int *index) {
+    CheckReadOptions(options);
+    static constexpr Options<RawQueue> kFromEndAndPeek = kFromEnd | kPeek;
+    if (options.AllSet(kFromEndAndPeek)) {
+      LOG(FATAL, "ReadMessageIndex(kFromEnd | kPeek) is not allowed\n");
+    }
+    return DoReadMessageIndex(options, index);
+  }
 
   // Retrieves ("allocates") a message that can then be written to the queue.
   // NOTE: the return value will be completely uninitialized
@@ -125,6 +147,22 @@
  private:
   struct MessageHeader;
 
+  // The public wrappers around these are inlined and do argument checking.
+  bool DoWriteMessage(void *msg, Options<RawQueue> options);
+  const void *DoReadMessage(Options<RawQueue> options);
+  const void *DoReadMessageIndex(Options<RawQueue> options, int *index);
+  void CheckReadOptions(Options<RawQueue> options) {
+    static constexpr Options<RawQueue> kValidOptions =
+        kPeek | kFromEnd | kNonBlock | kBlock;
+    if (!options.NoOthersSet(kValidOptions)) {
+      LOG(FATAL, "illegal read options in %x\n", options.printable());
+    }
+    static constexpr Options<RawQueue> kBlockChoices = kNonBlock | kBlock;
+    if (!options.ExactlyOneSet(kBlockChoices)) {
+      LOG(FATAL, "invalid read options %x\n", options.printable());
+    }
+  }
+
   // Adds 1 to the given index and handles wrapping correctly.
   int index_add1(int index);
 
@@ -175,7 +213,7 @@
   // Must be called with data_lock_ locked.
   // *read_data will be initialized.
   // Returns with a readable message in data_ or false.
-  bool ReadCommonStart(int options, int *index);
+  bool ReadCommonStart(Options<RawQueue> options, int *index);
   // Deals with setting/unsetting readable_ and writable_.
   // Must be called after data_lock_ has been unlocked.
   // read_data should be the same thing that was passed in to ReadCommonStart.
diff --git a/aos/linux_code/ipc_lib/raw_queue_test.cc b/aos/linux_code/ipc_lib/raw_queue_test.cc
index 65f2308..c85d36a 100644
--- a/aos/linux_code/ipc_lib/raw_queue_test.cc
+++ b/aos/linux_code/ipc_lib/raw_queue_test.cc
@@ -17,6 +17,8 @@
 #include "aos/common/logging/logging.h"
 #include "aos/common/die.h"
 #include "aos/common/util/thread.h"
+#include "aos/common/util/options.h"
+#include "aos/common/util/death_test_log_implementation.h"
 
 using ::testing::AssertionResult;
 using ::testing::AssertionSuccess;
@@ -266,7 +268,7 @@
   };
   struct MessageArgs {
     RawQueue *const queue;
-    int flags;
+    Options<RawQueue> flags;
     int16_t data;  // -1 means NULL expected
   };
   static void WriteTestMessage(MessageArgs *args, char *failure) {
@@ -278,8 +280,8 @@
     }
     msg->data = args->data;
     if (!args->queue->WriteMessage(msg, args->flags)) {
-      snprintf(failure, kFailureSize, "write_msg_free(%p, %p, %d) failed",
-               args->queue, msg, args->flags);
+      snprintf(failure, kFailureSize, "%p->WriteMessage(%p, %x) failed",
+               args->queue, msg, args->flags.printable());
     }
   }
   static void ReadTestMessage(MessageArgs *args, char *failure) {
@@ -310,47 +312,50 @@
  private:
   GlobalCoreInstance my_core;
 };
+
 char *RawQueueTest::fatal_failure;
 std::map<RawQueueTest::ChildID, RawQueueTest::ForkedProcess *>
     RawQueueTest::children_;
 constexpr time::Time RawQueueTest::kHangTime;
 constexpr time::Time RawQueueTest::kForkSleep;
 
+typedef RawQueueTest RawQueueDeathTest;
+
 TEST_F(RawQueueTest, Reading) {
   RawQueue *const queue = RawQueue::Fetch("Queue", sizeof(TestMessage), 1, 1);
-  MessageArgs args{queue, 0, -1};
+  MessageArgs args{queue, RawQueue::kBlock, -1};
 
   args.flags = RawQueue::kNonBlock;
   EXPECT_RETURNS(ReadTestMessage, &args);
   args.flags = RawQueue::kNonBlock | RawQueue::kPeek;
   EXPECT_RETURNS(ReadTestMessage, &args);
-  args.flags = 0;
+  args.flags = RawQueue::kBlock;
   EXPECT_HANGS(ReadTestMessage, &args);
-  args.flags = RawQueue::kPeek;
+  args.flags = RawQueue::kPeek | RawQueue::kBlock;
   EXPECT_HANGS(ReadTestMessage, &args);
   args.data = 254;
   args.flags = RawQueue::kBlock;
   EXPECT_RETURNS(WriteTestMessage, &args);
-  args.flags = RawQueue::kPeek;
+  args.flags = RawQueue::kPeek | RawQueue::kBlock;
   EXPECT_RETURNS(ReadTestMessage, &args);
-  args.flags = RawQueue::kPeek;
+  args.flags = RawQueue::kPeek | RawQueue::kBlock;
   EXPECT_RETURNS(ReadTestMessage, &args);
   args.flags = RawQueue::kPeek | RawQueue::kNonBlock;
   EXPECT_RETURNS(ReadTestMessage, &args);
-  args.flags = 0;
+  args.flags = RawQueue::kBlock;
   EXPECT_RETURNS(ReadTestMessage, &args);
-  args.flags = 0;
+  args.flags = RawQueue::kBlock;
   args.data = -1;
   EXPECT_HANGS(ReadTestMessage, &args);
   args.flags = RawQueue::kNonBlock;
   EXPECT_RETURNS(ReadTestMessage, &args);
-  args.flags = 0;
+  args.flags = RawQueue::kBlock;
   args.data = 971;
   EXPECT_RETURNS_FAILS(ReadTestMessage, &args);
 }
 TEST_F(RawQueueTest, Writing) {
   RawQueue *const queue = RawQueue::Fetch("Queue", sizeof(TestMessage), 1, 1);
-  MessageArgs args{queue, 0, 973};
+  MessageArgs args{queue, RawQueue::kBlock, 973};
 
   args.flags = RawQueue::kBlock;
   EXPECT_RETURNS(WriteTestMessage, &args);
@@ -360,28 +365,28 @@
   EXPECT_RETURNS_FAILS(WriteTestMessage, &args);
   args.flags = RawQueue::kNonBlock;
   EXPECT_RETURNS_FAILS(WriteTestMessage, &args);
-  args.flags = RawQueue::kPeek;
+  args.flags = RawQueue::kPeek | RawQueue::kBlock;
   EXPECT_RETURNS(ReadTestMessage, &args);
   args.data = 971;
   args.flags = RawQueue::kOverride;
   EXPECT_RETURNS(WriteTestMessage, &args);
   args.flags = RawQueue::kOverride;
   EXPECT_RETURNS(WriteTestMessage, &args);
-  args.flags = 0;
+  args.flags = RawQueue::kBlock;
   EXPECT_RETURNS(ReadTestMessage, &args);
   args.flags = RawQueue::kNonBlock;
   EXPECT_RETURNS(WriteTestMessage, &args);
-  args.flags = 0;
+  args.flags = RawQueue::kBlock;
   EXPECT_RETURNS(ReadTestMessage, &args);
   args.flags = RawQueue::kOverride;
   EXPECT_RETURNS(WriteTestMessage, &args);
-  args.flags = 0;
+  args.flags = RawQueue::kBlock;
   EXPECT_RETURNS(ReadTestMessage, &args);
 }
 
 TEST_F(RawQueueTest, MultiRead) {
   RawQueue *const queue = RawQueue::Fetch("Queue", sizeof(TestMessage), 1, 1);
-  MessageArgs args{queue, 0, 1323};
+  MessageArgs args{queue, RawQueue::kBlock, 1323};
 
   args.flags = RawQueue::kBlock;
   EXPECT_RETURNS(WriteTestMessage, &args);
@@ -402,16 +407,17 @@
   // message to use for it).
   TestMessage *msg = static_cast<TestMessage *>(queue->GetMessage());
   ASSERT_NE(nullptr, msg);
-  ASSERT_TRUE(queue->WriteMessage(msg, 0));
-  const void *read_msg = queue->ReadMessage(0);
+  ASSERT_TRUE(queue->WriteMessage(msg, RawQueue::kBlock));
+  const void *read_msg = queue->ReadMessage(RawQueue::kBlock);
   EXPECT_NE(nullptr, read_msg);
   msg = static_cast<TestMessage *>(queue->GetMessage());
   queue->FreeMessage(read_msg);
   ASSERT_NE(nullptr, msg);
-  ASSERT_TRUE(queue->WriteMessage(msg, 0));
+  ASSERT_TRUE(queue->WriteMessage(msg, RawQueue::kBlock));
 
   int index = 0;
-  const void *second_read_msg = queue->ReadMessageIndex(0, &index);
+  const void *second_read_msg =
+      queue->ReadMessageIndex(RawQueue::kBlock, &index);
   EXPECT_NE(nullptr, second_read_msg);
   EXPECT_NE(read_msg, second_read_msg)
       << "We already took that message out of the queue.";
@@ -424,7 +430,8 @@
   RawQueue *const queue = RawQueue::Fetch("Queue", sizeof(TestMessage),
                                           1, 2, 2, 2, &recycle_queue);
   ASSERT_NE(reinterpret_cast<RawQueue *>(23), recycle_queue);
-  MessageArgs args{queue, 0, 973}, recycle{recycle_queue, 0, 973};
+  MessageArgs args{queue, RawQueue::kBlock, 973},
+      recycle{recycle_queue, RawQueue::kBlock, 973};
 
   args.flags = RawQueue::kBlock;
   EXPECT_RETURNS(WriteTestMessage, &args);
@@ -450,7 +457,7 @@
   EXPECT_HANGS(ReadTestMessage, &recycle);
 
   args.data = 254;
-  args.flags = RawQueue::kPeek;
+  args.flags = RawQueue::kPeek | RawQueue::kBlock;
   EXPECT_RETURNS(ReadTestMessage, &args);
   recycle.flags = RawQueue::kBlock;
   EXPECT_HANGS(ReadTestMessage, &recycle);
@@ -524,8 +531,8 @@
   queue->FreeMessage(peek_message);
 
   index = 0;
-  peek_message = static_cast<const TestMessage *>(queue->ReadMessageIndex(
-      RawQueue::kNonBlock | RawQueue::kPeek | RawQueue::kFromEnd, &index));
+  peek_message = static_cast<const TestMessage *>(queue->ReadMessage(
+      RawQueue::kNonBlock | RawQueue::kPeek | RawQueue::kFromEnd));
   message = static_cast<const TestMessage *>(queue->ReadMessageIndex(
       RawQueue::kNonBlock | RawQueue::kFromEnd, &index));
   ASSERT_NE(nullptr, message);
@@ -561,8 +568,8 @@
   queue->FreeMessage(peek_message);
 
   index = 0;
-  peek_message = static_cast<const TestMessage *>(queue->ReadMessageIndex(
-      RawQueue::kNonBlock | RawQueue::kPeek | RawQueue::kFromEnd, &index));
+  peek_message = static_cast<const TestMessage *>(queue->ReadMessage(
+      RawQueue::kNonBlock | RawQueue::kPeek | RawQueue::kFromEnd));
   message = static_cast<const TestMessage *>(queue->ReadMessageIndex(
       RawQueue::kNonBlock | RawQueue::kFromEnd, &index));
   ASSERT_NE(nullptr, message);
@@ -594,8 +601,8 @@
   queue->FreeMessage(peek_message);
 
   index = 0;
-  peek_message = static_cast<const TestMessage *>(queue->ReadMessageIndex(
-      RawQueue::kNonBlock | RawQueue::kPeek | RawQueue::kFromEnd, &index));
+  peek_message = static_cast<const TestMessage *>(queue->ReadMessage(
+      RawQueue::kNonBlock | RawQueue::kPeek | RawQueue::kFromEnd));
   message = static_cast<const TestMessage *>(queue->ReadMessageIndex(
       RawQueue::kNonBlock | RawQueue::kFromEnd, &index));
   ASSERT_NE(nullptr, message);
@@ -639,8 +646,8 @@
   queue->FreeMessage(peek_message);
 
   index = 0;
-  peek_message = static_cast<const TestMessage *>(queue->ReadMessageIndex(
-      RawQueue::kNonBlock | RawQueue::kPeek | RawQueue::kFromEnd, &index));
+  peek_message = static_cast<const TestMessage *>(queue->ReadMessage(
+      RawQueue::kNonBlock | RawQueue::kPeek | RawQueue::kFromEnd));
   message = static_cast<const TestMessage *>(queue->ReadMessageIndex(
       RawQueue::kNonBlock | RawQueue::kFromEnd, &index));
   ASSERT_NE(nullptr, message);
@@ -674,8 +681,8 @@
   queue->FreeMessage(peek_message);
 
   index = 0;
-  peek_message = static_cast<const TestMessage *>(queue->ReadMessageIndex(
-      RawQueue::kNonBlock | RawQueue::kPeek | RawQueue::kFromEnd, &index));
+  peek_message = static_cast<const TestMessage *>(queue->ReadMessage(
+      RawQueue::kNonBlock | RawQueue::kPeek | RawQueue::kFromEnd));
   message = static_cast<const TestMessage *>(queue->ReadMessageIndex(
       RawQueue::kNonBlock | RawQueue::kFromEnd, &index));
   ASSERT_NE(nullptr, message);
@@ -731,8 +738,8 @@
   queue->FreeMessage(peek_message);
 
   index = 0;
-  peek_message = static_cast<const TestMessage *>(queue->ReadMessageIndex(
-      RawQueue::kNonBlock | RawQueue::kPeek | RawQueue::kFromEnd, &index));
+  peek_message = static_cast<const TestMessage *>(queue->ReadMessage(
+      RawQueue::kNonBlock | RawQueue::kPeek | RawQueue::kFromEnd));
   message = static_cast<const TestMessage *>(queue->ReadMessageIndex(
       RawQueue::kNonBlock | RawQueue::kFromEnd, &index));
   ASSERT_NE(nullptr, message);
@@ -768,8 +775,8 @@
   queue->FreeMessage(peek_message);
 
   index = 0;
-  peek_message = static_cast<const TestMessage *>(queue->ReadMessageIndex(
-      RawQueue::kNonBlock | RawQueue::kPeek | RawQueue::kFromEnd, &index));
+  peek_message = static_cast<const TestMessage *>(queue->ReadMessage(
+      RawQueue::kNonBlock | RawQueue::kPeek | RawQueue::kFromEnd));
   message = static_cast<const TestMessage *>(queue->ReadMessageIndex(
       RawQueue::kNonBlock | RawQueue::kFromEnd, &index));
   ASSERT_NE(nullptr, message);
@@ -817,8 +824,8 @@
   queue->FreeMessage(peek_message);
 
   index = 0;
-  peek_message = static_cast<const TestMessage *>(queue->ReadMessageIndex(
-      RawQueue::kNonBlock | RawQueue::kPeek | RawQueue::kFromEnd, &index));
+  peek_message = static_cast<const TestMessage *>(queue->ReadMessage(
+      RawQueue::kNonBlock | RawQueue::kPeek | RawQueue::kFromEnd));
   message = static_cast<const TestMessage *>(queue->ReadMessageIndex(
       RawQueue::kNonBlock | RawQueue::kFromEnd, &index));
   ASSERT_NE(nullptr, message);
@@ -856,8 +863,8 @@
   queue->FreeMessage(peek_message);
 
   index = 0;
-  peek_message = static_cast<const TestMessage *>(queue->ReadMessageIndex(
-      RawQueue::kNonBlock | RawQueue::kPeek | RawQueue::kFromEnd, &index));
+  peek_message = static_cast<const TestMessage *>(queue->ReadMessage(
+      RawQueue::kNonBlock | RawQueue::kPeek | RawQueue::kFromEnd));
   message = static_cast<const TestMessage *>(queue->ReadMessageIndex(
       RawQueue::kNonBlock | RawQueue::kFromEnd, &index));
   ASSERT_NE(nullptr, message);
@@ -933,8 +940,12 @@
   PushMessage(queue, 971);
   int free_before = queue->FreeMessages();
 
-  const void *const message1 = queue->ReadMessage(RawQueue::kPeek);
-  const void *const message2 = queue->ReadMessage(RawQueue::kPeek);
+  const void *const message1 =
+      queue->ReadMessage(RawQueue::kPeek | RawQueue::kNonBlock);
+  const void *const message2 =
+      queue->ReadMessage(RawQueue::kPeek | RawQueue::kNonBlock);
+  ASSERT_NE(nullptr, message1);
+  ASSERT_NE(nullptr, message2);
   EXPECT_EQ(free_before, queue->FreeMessages());
   util::FunctionThread t1([message1, queue](util::Thread *) {
     queue->FreeMessage(message1);
@@ -949,5 +960,61 @@
   EXPECT_EQ(free_before, queue->FreeMessages());
 }
 
+TEST_F(RawQueueDeathTest, OptionsValidation) {
+  RawQueue *const queue = RawQueue::Fetch("Queue", 1, 1, 1);
+
+  EXPECT_DEATH(
+      {
+        logging::AddImplementation(new util::DeathTestLogImplementation());
+        queue->WriteMessage(nullptr, RawQueue::kPeek);
+      },
+      ".*illegal write option.*");
+  EXPECT_DEATH(
+      {
+        logging::AddImplementation(new util::DeathTestLogImplementation());
+        queue->WriteMessage(nullptr, RawQueue::kFromEnd);
+      },
+      ".*illegal write option.*");
+  EXPECT_DEATH(
+      {
+        logging::AddImplementation(new util::DeathTestLogImplementation());
+        queue->WriteMessage(nullptr, RawQueue::kPeek | RawQueue::kFromEnd);
+      },
+      ".*illegal write option.*");
+  EXPECT_DEATH(
+      {
+        logging::AddImplementation(new util::DeathTestLogImplementation());
+        queue->WriteMessage(nullptr, RawQueue::kNonBlock | RawQueue::kBlock);
+      },
+      ".*invalid write option.*");
+
+  EXPECT_DEATH(
+      {
+        logging::AddImplementation(new util::DeathTestLogImplementation());
+        queue->ReadMessageIndex(
+            RawQueue::kBlock | RawQueue::kFromEnd | RawQueue::kPeek, nullptr);
+      },
+      ".*ReadMessageIndex.*is not allowed.*");
+  EXPECT_DEATH(
+      {
+        logging::AddImplementation(new util::DeathTestLogImplementation());
+        queue->ReadMessageIndex(RawQueue::kOverride, nullptr);
+      },
+      ".*illegal read option.*");
+  EXPECT_DEATH(
+      {
+        logging::AddImplementation(new util::DeathTestLogImplementation());
+        queue->ReadMessageIndex(RawQueue::kOverride | RawQueue::kBlock,
+                                nullptr);
+      },
+      ".*illegal read option.*");
+  EXPECT_DEATH(
+      {
+        logging::AddImplementation(new util::DeathTestLogImplementation());
+        queue->ReadMessage(RawQueue::kNonBlock | RawQueue::kBlock);
+      },
+      ".*invalid read option.*");
+}
+
 }  // namespace testing
 }  // namespace aos
diff --git a/aos/linux_code/logging/linux_logging.cc b/aos/linux_code/logging/linux_logging.cc
index cdb052a..2bd5bce 100644
--- a/aos/linux_code/logging/linux_logging.cc
+++ b/aos/linux_code/logging/linux_logging.cc
@@ -77,7 +77,7 @@
   AddImplementation(new LinuxQueueLogImplementation());
 }
 
-const LogMessage *ReadNext(int flags, int *index) {
+const LogMessage *ReadNext(Options<RawQueue> flags, int *index) {
   return static_cast<const LogMessage *>(queue->ReadMessageIndex(flags, index));
 }
 
@@ -85,7 +85,7 @@
   return ReadNext(RawQueue::kBlock);
 }
 
-const LogMessage *ReadNext(int flags) {
+const LogMessage *ReadNext(Options<RawQueue> flags) {
   const LogMessage *r = NULL;
   do {
     r = static_cast<const LogMessage *>(queue->ReadMessage(flags));
diff --git a/aos/linux_code/logging/linux_logging.h b/aos/linux_code/logging/linux_logging.h
index 3dc8763..63eeaf1 100644
--- a/aos/linux_code/logging/linux_logging.h
+++ b/aos/linux_code/logging/linux_logging.h
@@ -2,8 +2,12 @@
 #define AOS_LINUX_CODE_LOGGING_LOGGING_H_
 
 #include "aos/common/logging/logging_impl.h"
+#include "aos/common/util/options.h"
 
 namespace aos {
+
+class RawQueue;
+
 namespace logging {
 namespace linux_code {
 
@@ -16,8 +20,8 @@
 // Fairly simple wrappers around the raw queue calls.
 
 // This one never returns NULL if flags contains BLOCK.
-const LogMessage *ReadNext(int flags);
-const LogMessage *ReadNext(int flags, int *index);
+const LogMessage *ReadNext(Options<RawQueue> flags);
+const LogMessage *ReadNext(Options<RawQueue> flags, int *index);
 const LogMessage *ReadNext();
 LogMessage *Get();
 void Free(const LogMessage *msg);
diff --git a/aos/linux_code/queue-tmpl.h b/aos/linux_code/queue-tmpl.h
index 522bf6b..719af5d 100644
--- a/aos/linux_code/queue-tmpl.h
+++ b/aos/linux_code/queue-tmpl.h
@@ -72,8 +72,10 @@
 template <class T>
 bool Queue<T>::FetchLatest() {
   Init();
-  const T *msg = static_cast<const T *>(queue_->ReadMessageIndex(
-          RawQueue::kFromEnd | RawQueue::kNonBlock, &index_));
+  static constexpr Options<RawQueue> kOptions =
+      RawQueue::kFromEnd | RawQueue::kNonBlock;
+  const T *msg =
+      static_cast<const T *>(queue_->ReadMessageIndex(kOptions, &index_));
   // Only update the internal pointer if we got a new message.
   if (msg != NULL && msg != queue_msg_.get()) {
     queue_msg_.reset(msg);