Add android/utils/eintr_wrapper.h

Add a new Android-specific header that defines two macros to
handle EINTR in a consistent way, as well as allow detecting
when a system call loops too many times and exit with a fatal
error message when that happens.

+ Unit tests.

+ Update existing code under android/ which uses to deal directly
  with EINTR to use the new HANDLE_EINTR() and IGNORE_EINTR()

+ Remove EINTR checks for functions that call socket_xxx() functions
  which already loop around EINTR.

Change-Id: I1d2ee64d9743a2edc506f616465ea091878db620
diff --git a/android/async-socket.c b/android/async-socket.c
index 92c2ef7..107cdbb 100644
--- a/android/async-socket.c
+++ b/android/async-socket.c
@@ -20,10 +20,11 @@
  * a TCP port forwarding, enabled by ADB.
  */
 
-#include "android/utils/debug.h"
 #include "android/async-socket-connector.h"
 #include "android/async-socket.h"
-#include "utils/panic.h"
+#include "android/utils/debug.h"
+#include "android/utils/eintr_wrapper.h"
+#include "android/utils/panic.h"
 #include "android/iolooper.h"
 
 #define  E(...)    derror(__VA_ARGS__)
@@ -827,13 +828,10 @@
     }
 
     /* Read next chunk of data. */
-    int res = socket_recv(as->fd, asr->buffer + asr->transferred,
-                          asr->to_transfer - asr->transferred);
-    while (res < 0 && errno == EINTR) {
-        res = socket_recv(as->fd, asr->buffer + asr->transferred,
-                          asr->to_transfer - asr->transferred);
-    }
-
+    int res = HANDLE_EINTR(
+            socket_recv(as->fd,
+                        asr->buffer + asr->transferred,
+                        asr->to_transfer - asr->transferred));
     if (res == 0) {
         /* Socket has been disconnected. */
         errno = ECONNRESET;
@@ -937,13 +935,10 @@
     }
 
     /* Write next chunk of data. */
-    int res = socket_send(as->fd, asw->buffer + asw->transferred,
-                          asw->to_transfer - asw->transferred);
-    while (res < 0 && errno == EINTR) {
-        res = socket_send(as->fd, asw->buffer + asw->transferred,
-                          asw->to_transfer - asw->transferred);
-    }
-
+    int res = HANDLE_EINTR(
+            socket_send(as->fd,
+                        asw->buffer + asw->transferred,
+                        asw->to_transfer - asw->transferred));
     if (res == 0) {
         /* Socket has been disconnected. */
         errno = ECONNRESET;
diff --git a/android/async-utils.c b/android/async-utils.c
index 9732111..9dd223d 100644
--- a/android/async-utils.c
+++ b/android/async-utils.c
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 #include "android/async-utils.h"
+#include "android/utils/eintr_wrapper.h"
 #include "unistd.h"
 
 void
@@ -40,15 +41,16 @@
     }
 
     do {
-        ret = socket_recv(ar->io->fd, ar->buffer + ar->pos, ar->buffsize - ar->pos);
+        ret = HANDLE_EINTR(
+                socket_recv(ar->io->fd,
+                            ar->buffer + ar->pos,
+                            ar->buffsize - ar->pos));
         if (ret == 0) {
             /* disconnection ! */
             errno = ECONNRESET;
             return ASYNC_ERROR;
         }
         if (ret < 0) {
-            if (errno == EINTR) /* loop on EINTR */
-                continue;
             if (errno == EWOULDBLOCK || errno == EAGAIN) {
                 loopIo_wantRead(ar->io);
                 return ASYNC_NEED_MORE;
@@ -87,15 +89,16 @@
     }
 
     do {
-        ret = socket_send(aw->io->fd, aw->buffer + aw->pos, aw->buffsize - aw->pos);
+        ret = HANDLE_EINTR(
+                socket_send(aw->io->fd,
+                            aw->buffer + aw->pos,
+                            aw->buffsize - aw->pos));
         if (ret == 0) {
             /* disconnection ! */
             errno = ECONNRESET;
             return ASYNC_ERROR;
         }
         if (ret < 0) {
-            if (errno == EINTR) /* loop on EINTR */
-                continue;
             if (errno == EWOULDBLOCK || errno == EAGAIN) {
                 return ASYNC_NEED_MORE;
             }
@@ -137,15 +140,13 @@
 
     do {
         char ch;
-        ret = socket_recv(alr->io->fd, &ch, 1);
+        ret = HANDLE_EINTR(socket_recv(alr->io->fd, &ch, 1));
         if (ret == 0) {
             /* disconnection ! */
             errno = ECONNRESET;
             return ASYNC_ERROR;
         }
         if (ret < 0) {
-            if (errno == EINTR) /* loop on EINTR */
-                continue;
             if (errno == EWOULDBLOCK || errno == EAGAIN) {
                 loopIo_wantRead(alr->io);
                 return ASYNC_NEED_MORE;
diff --git a/android/camera/camera-capture-linux.c b/android/camera/camera-capture-linux.c
index e56ffae..c3e8570 100644
--- a/android/camera/camera-capture-linux.c
+++ b/android/camera/camera-capture-linux.c
@@ -25,6 +25,7 @@
 #include <sys/ioctl.h>
 #include "android/camera/camera-capture.h"
 #include "android/camera/camera-format-converters.h"
+#include "android/utils/eintr_wrapper.h"
 
 #define  E(...)    derror(__VA_ARGS__)
 #define  W(...)    dwarning(__VA_ARGS__)
@@ -145,11 +146,7 @@
 /* IOCTL wrapper. */
 static int
 _xioctl(int fd, int request, void *arg) {
-  int r;
-  do {
-      r = ioctl(fd, request, arg);
-  } while (-1 == r && EINTR == errno);
-  return r;
+    return HANDLE_EINTR(ioctl(fd, request, arg));
 }
 
 /* Frees resource allocated for QemuPixelFormat instance, excluding the instance
@@ -1031,7 +1028,7 @@
                 break;
             } else if (errno == EAGAIN) {
                 return 1;   // Tells the caller to repeat.
-            } else if (errno != EINTR && errno != EIO) {
+            } else if (errno != EIO) {
                 E("%s: VIDIOC_DQBUF on camera '%s' has failed: %s",
                   __FUNCTION__, cd->device_name, strerror(errno));
                 return -1;
diff --git a/android/camera/camera-common.h b/android/camera/camera-common.h
index de09045..8b17628 100755
--- a/android/camera/camera-common.h
+++ b/android/camera/camera-common.h
@@ -1,206 +1,206 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
+/*

+ * Copyright (C) 2011 The Android Open Source Project

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

 #ifndef ANDROID_CAMERA_CAMERA_COMMON_H_

 #define ANDROID_CAMERA_CAMERA_COMMON_H_

-
-/*
- * Contains declarations of platform-independent the stuff that is used in
- * camera emulation.
- */
-
-#include "qemu-common.h"
-#include "android/utils/debug.h"
-#include "android/utils/misc.h"
-#include "android/utils/system.h"
-#ifdef _WIN32
-/* Include declarations that are missing in non-Linux headers. */
-#include "android/camera/camera-win.h"
-#elif _DARWIN_C_SOURCE
-/* Include declarations that are missing in non-Linux headers. */
-#include "android/camera/camera-win.h"
-#else
-#include <linux/videodev2.h>
-#endif  /* _WIN32 */
-
-/*
- * These are missing in the current linux/videodev2.h
- */
-
-#ifndef V4L2_PIX_FMT_YVYU
-#define V4L2_PIX_FMT_YVYU    v4l2_fourcc('Y', 'V', 'Y', 'U')
-#endif /* V4L2_PIX_FMT_YVYU */
-#ifndef V4L2_PIX_FMT_VYUY
-#define V4L2_PIX_FMT_VYUY    v4l2_fourcc('V', 'Y', 'U', 'Y')
-#endif /* V4L2_PIX_FMT_VYUY */
-#ifndef V4L2_PIX_FMT_YUY2
-#define V4L2_PIX_FMT_YUY2    v4l2_fourcc('Y', 'U', 'Y', '2')
-#endif /* V4L2_PIX_FMT_YUY2 */
-#ifndef V4L2_PIX_FMT_YUNV
-#define V4L2_PIX_FMT_YUNV    v4l2_fourcc('Y', 'U', 'N', 'V')
-#endif /* V4L2_PIX_FMT_YUNV */
-#ifndef V4L2_PIX_FMT_V422
-#define V4L2_PIX_FMT_V422    v4l2_fourcc('V', '4', '2', '2')
-#endif /* V4L2_PIX_FMT_V422 */
-#ifndef V4L2_PIX_FMT_YYVU
-#define V4L2_PIX_FMT_YYVU    v4l2_fourcc('Y', 'Y', 'V', 'U')
-#endif /* V4L2_PIX_FMT_YYVU */
-#ifndef V4L2_PIX_FMT_SGBRG8
-#define V4L2_PIX_FMT_SGBRG8  v4l2_fourcc('G', 'B', 'R', 'G')
-#endif  /* V4L2_PIX_FMT_SGBRG8 */
-#ifndef V4L2_PIX_FMT_SGRBG8
-#define V4L2_PIX_FMT_SGRBG8  v4l2_fourcc('G', 'R', 'B', 'G')
-#endif  /* V4L2_PIX_FMT_SGRBG8 */
-#ifndef V4L2_PIX_FMT_SRGGB8
-#define V4L2_PIX_FMT_SRGGB8  v4l2_fourcc('R', 'G', 'G', 'B')
-#endif  /* V4L2_PIX_FMT_SRGGB8 */
-#ifndef V4L2_PIX_FMT_SBGGR10
-#define V4L2_PIX_FMT_SBGGR10 v4l2_fourcc('B', 'G', '1', '\0')
-#endif  /* V4L2_PIX_FMT_SBGGR10 */
-#ifndef V4L2_PIX_FMT_SGBRG10
-#define V4L2_PIX_FMT_SGBRG10 v4l2_fourcc('G', 'B', '1', '\0')
-#endif  /* V4L2_PIX_FMT_SGBRG10 */
-#ifndef V4L2_PIX_FMT_SGRBG10
-#define V4L2_PIX_FMT_SGRBG10 v4l2_fourcc('B', 'A', '1', '\0')
-#endif  /* V4L2_PIX_FMT_SGRBG10 */
-#ifndef V4L2_PIX_FMT_SRGGB10
-#define V4L2_PIX_FMT_SRGGB10 v4l2_fourcc('R', 'G', '1', '\0')
-#endif  /* V4L2_PIX_FMT_SRGGB10 */
-#ifndef V4L2_PIX_FMT_SBGGR12
-#define V4L2_PIX_FMT_SBGGR12 v4l2_fourcc('B', 'G', '1', '2')
-#endif  /* V4L2_PIX_FMT_SBGGR12 */
-#ifndef V4L2_PIX_FMT_SGBRG12
-#define V4L2_PIX_FMT_SGBRG12 v4l2_fourcc('G', 'B', '1', '2')
-#endif  /* V4L2_PIX_FMT_SGBRG12 */
-#ifndef V4L2_PIX_FMT_SGRBG12
-#define V4L2_PIX_FMT_SGRBG12 v4l2_fourcc('B', 'A', '1', '2')
-#endif  /* V4L2_PIX_FMT_SGRBG12 */
-#ifndef V4L2_PIX_FMT_SRGGB12
-#define V4L2_PIX_FMT_SRGGB12 v4l2_fourcc('R', 'G', '1', '2')
-#endif  /* V4L2_PIX_FMT_SRGGB12 */
-
-/* Describes framebuffer, used by the client of camera capturing API.
- * This descritptor is used in camera_device_read_frame call.
- */
-typedef struct ClientFrameBuffer {
-    /* Pixel format used in the client framebuffer. */
-    uint32_t    pixel_format;
-    /* Address of the client framebuffer. */
-    void*       framebuffer;
-} ClientFrameBuffer;
-
-/* Describes frame dimensions.
- */
-typedef struct CameraFrameDim {
-    /* Frame width. */
-    int     width;
-    /* Frame height. */
-    int     height;
-} CameraFrameDim;
-
-/* Camera information descriptor, containing properties of a camera connected
- * to the host.
- *
- * Instances of this structure are created during camera device enumerations,
- * and are considered to be constant everywhere else. The only exception to this
- * rule is changing the 'in_use' flag during creation / destruction of a service
- * representing that camera.
- */
-typedef struct CameraInfo {
-    /* User-friendly camera display name. */
-    char*               display_name;
-    /* Device name for the camera. */
-    char*               device_name;
-    /* Input channel for the camera. */
-    int                 inp_channel;
-    /* Pixel format chosen for the camera. */
-    uint32_t            pixel_format;
-    /* Direction the camera is facing: 'front', or 'back' */
-    char*               direction;
-    /* Array of frame sizes supported for the pixel format chosen for the camera.
-     * The size of the array is defined by the frame_sizes_num field of this
-     * structure. */
-    CameraFrameDim*     frame_sizes;
-    /* Number of frame sizes supported for the pixel format chosen
-     * for the camera. */
-    int                 frame_sizes_num;
-    /* In use status. When there is a camera service created for this camera,
-     * "in use" is set to one. Otherwise this flag is zet to 0. */
-    int                 in_use;
-} CameraInfo;
-
-/* Allocates CameraInfo instance. */
-static __inline__ CameraInfo* _camera_info_alloc(void)
-{
-    CameraInfo* ci;
-    ANEW0(ci);
-    return ci;
-}
-
-/* Frees all resources allocated for CameraInfo instance (including the
- * instance itself).
- */
-static __inline__ void _camera_info_free(CameraInfo* ci)
-{
-    if (ci != NULL) {
-        if (ci->display_name != NULL)
-            free(ci->display_name);
-        if (ci->device_name != NULL)
-            free(ci->device_name);
-        if (ci->direction != NULL)
-            free(ci->direction);
-        if (ci->frame_sizes != NULL)
-            free(ci->frame_sizes);
-        AFREE(ci);
-    }
-}
+

+/*

+ * Contains declarations of platform-independent the stuff that is used in

+ * camera emulation.

+ */

+

+#include "qemu-common.h"

+#include "android/utils/debug.h"

+#include "android/utils/misc.h"

+#include "android/utils/system.h"

+#ifdef _WIN32

+/* Include declarations that are missing in non-Linux headers. */

+#include "android/camera/camera-win.h"

+#elif _DARWIN_C_SOURCE

+/* Include declarations that are missing in non-Linux headers. */

+#include "android/camera/camera-win.h"

+#else

+#include <linux/videodev2.h>

+#endif  /* _WIN32 */

+

+/*

+ * These are missing in the current linux/videodev2.h

+ */

+

+#ifndef V4L2_PIX_FMT_YVYU

+#define V4L2_PIX_FMT_YVYU    v4l2_fourcc('Y', 'V', 'Y', 'U')

+#endif /* V4L2_PIX_FMT_YVYU */

+#ifndef V4L2_PIX_FMT_VYUY

+#define V4L2_PIX_FMT_VYUY    v4l2_fourcc('V', 'Y', 'U', 'Y')

+#endif /* V4L2_PIX_FMT_VYUY */

+#ifndef V4L2_PIX_FMT_YUY2

+#define V4L2_PIX_FMT_YUY2    v4l2_fourcc('Y', 'U', 'Y', '2')

+#endif /* V4L2_PIX_FMT_YUY2 */

+#ifndef V4L2_PIX_FMT_YUNV

+#define V4L2_PIX_FMT_YUNV    v4l2_fourcc('Y', 'U', 'N', 'V')

+#endif /* V4L2_PIX_FMT_YUNV */

+#ifndef V4L2_PIX_FMT_V422

+#define V4L2_PIX_FMT_V422    v4l2_fourcc('V', '4', '2', '2')

+#endif /* V4L2_PIX_FMT_V422 */

+#ifndef V4L2_PIX_FMT_YYVU

+#define V4L2_PIX_FMT_YYVU    v4l2_fourcc('Y', 'Y', 'V', 'U')

+#endif /* V4L2_PIX_FMT_YYVU */

+#ifndef V4L2_PIX_FMT_SGBRG8

+#define V4L2_PIX_FMT_SGBRG8  v4l2_fourcc('G', 'B', 'R', 'G')

+#endif  /* V4L2_PIX_FMT_SGBRG8 */

+#ifndef V4L2_PIX_FMT_SGRBG8

+#define V4L2_PIX_FMT_SGRBG8  v4l2_fourcc('G', 'R', 'B', 'G')

+#endif  /* V4L2_PIX_FMT_SGRBG8 */

+#ifndef V4L2_PIX_FMT_SRGGB8

+#define V4L2_PIX_FMT_SRGGB8  v4l2_fourcc('R', 'G', 'G', 'B')

+#endif  /* V4L2_PIX_FMT_SRGGB8 */

+#ifndef V4L2_PIX_FMT_SBGGR10

+#define V4L2_PIX_FMT_SBGGR10 v4l2_fourcc('B', 'G', '1', '\0')

+#endif  /* V4L2_PIX_FMT_SBGGR10 */

+#ifndef V4L2_PIX_FMT_SGBRG10

+#define V4L2_PIX_FMT_SGBRG10 v4l2_fourcc('G', 'B', '1', '\0')

+#endif  /* V4L2_PIX_FMT_SGBRG10 */

+#ifndef V4L2_PIX_FMT_SGRBG10

+#define V4L2_PIX_FMT_SGRBG10 v4l2_fourcc('B', 'A', '1', '\0')

+#endif  /* V4L2_PIX_FMT_SGRBG10 */

+#ifndef V4L2_PIX_FMT_SRGGB10

+#define V4L2_PIX_FMT_SRGGB10 v4l2_fourcc('R', 'G', '1', '\0')

+#endif  /* V4L2_PIX_FMT_SRGGB10 */

+#ifndef V4L2_PIX_FMT_SBGGR12

+#define V4L2_PIX_FMT_SBGGR12 v4l2_fourcc('B', 'G', '1', '2')

+#endif  /* V4L2_PIX_FMT_SBGGR12 */

+#ifndef V4L2_PIX_FMT_SGBRG12

+#define V4L2_PIX_FMT_SGBRG12 v4l2_fourcc('G', 'B', '1', '2')

+#endif  /* V4L2_PIX_FMT_SGBRG12 */

+#ifndef V4L2_PIX_FMT_SGRBG12

+#define V4L2_PIX_FMT_SGRBG12 v4l2_fourcc('B', 'A', '1', '2')

+#endif  /* V4L2_PIX_FMT_SGRBG12 */

+#ifndef V4L2_PIX_FMT_SRGGB12

+#define V4L2_PIX_FMT_SRGGB12 v4l2_fourcc('R', 'G', '1', '2')

+#endif  /* V4L2_PIX_FMT_SRGGB12 */

+

+/* Describes framebuffer, used by the client of camera capturing API.

+ * This descritptor is used in camera_device_read_frame call.

+ */

+typedef struct ClientFrameBuffer {

+    /* Pixel format used in the client framebuffer. */

+    uint32_t    pixel_format;

+    /* Address of the client framebuffer. */

+    void*       framebuffer;

+} ClientFrameBuffer;

+

+/* Describes frame dimensions.

+ */

+typedef struct CameraFrameDim {

+    /* Frame width. */

+    int     width;

+    /* Frame height. */

+    int     height;

+} CameraFrameDim;

+

+/* Camera information descriptor, containing properties of a camera connected

+ * to the host.

+ *

+ * Instances of this structure are created during camera device enumerations,

+ * and are considered to be constant everywhere else. The only exception to this

+ * rule is changing the 'in_use' flag during creation / destruction of a service

+ * representing that camera.

+ */

+typedef struct CameraInfo {

+    /* User-friendly camera display name. */

+    char*               display_name;

+    /* Device name for the camera. */

+    char*               device_name;

+    /* Input channel for the camera. */

+    int                 inp_channel;

+    /* Pixel format chosen for the camera. */

+    uint32_t            pixel_format;

+    /* Direction the camera is facing: 'front', or 'back' */

+    char*               direction;

+    /* Array of frame sizes supported for the pixel format chosen for the camera.

+     * The size of the array is defined by the frame_sizes_num field of this

+     * structure. */

+    CameraFrameDim*     frame_sizes;

+    /* Number of frame sizes supported for the pixel format chosen

+     * for the camera. */

+    int                 frame_sizes_num;

+    /* In use status. When there is a camera service created for this camera,

+     * "in use" is set to one. Otherwise this flag is zet to 0. */

+    int                 in_use;

+} CameraInfo;

+

+/* Allocates CameraInfo instance. */

+static __inline__ CameraInfo* _camera_info_alloc(void)

+{

+    CameraInfo* ci;

+    ANEW0(ci);

+    return ci;

+}

+

+/* Frees all resources allocated for CameraInfo instance (including the

+ * instance itself).

+ */

+static __inline__ void _camera_info_free(CameraInfo* ci)

+{

+    if (ci != NULL) {

+        if (ci->display_name != NULL)

+            free(ci->display_name);

+        if (ci->device_name != NULL)

+            free(ci->device_name);

+        if (ci->direction != NULL)

+            free(ci->direction);

+        if (ci->frame_sizes != NULL)

+            free(ci->frame_sizes);

+        AFREE(ci);

+    }

+}

 

 /* Describes a connected camera device.

  * This is a pratform-independent camera device descriptor that is used in

  * the camera API.

  */

-typedef struct CameraDevice {
-    /* Opaque pointer used by the camera capturing API. */
-    void*       opaque;
-} CameraDevice;
-
-/* Returns current time in microseconds. */
-static __inline__ uint64_t
-_get_timestamp(void)
-{
-    struct timeval t;
-    t.tv_sec = t.tv_usec = 0;
-    gettimeofday(&t, NULL);
-    return (uint64_t)t.tv_sec * 1000000LL + t.tv_usec;
-}
-
-/* Sleeps for the given amount of milliseconds */
-static __inline__ void
-_camera_sleep(int millisec)
-{
-    struct timeval t;
-    const uint64_t wake_at = _get_timestamp() + (uint64_t)millisec * 1000;
-    do {
-        const uint64_t stamp = _get_timestamp();
-        if ((stamp / 1000) >= (wake_at / 1000)) {
-            break;
-        }
-        t.tv_sec = (wake_at - stamp) / 1000000;
-        t.tv_usec = (wake_at - stamp) - (uint64_t)t.tv_sec * 1000000;
-    } while (select(0, NULL, NULL, NULL, &t) < 0 && errno == EINTR);
-}
+typedef struct CameraDevice {

+    /* Opaque pointer used by the camera capturing API. */

+    void*       opaque;

+} CameraDevice;

 

-#endif  /* ANDROID_CAMERA_CAMERA_COMMON_H_ */
+/* Returns current time in microseconds. */

+static __inline__ uint64_t

+_get_timestamp(void)

+{

+    struct timeval t;

+    t.tv_sec = t.tv_usec = 0;

+    gettimeofday(&t, NULL);

+    return (uint64_t)t.tv_sec * 1000000LL + t.tv_usec;

+}

+

+/* Sleeps for the given amount of milliseconds */

+static __inline__ void

+_camera_sleep(int millisec)

+{

+    struct timeval t;

+    const uint64_t wake_at = _get_timestamp() + (uint64_t)millisec * 1000;

+    do {

+        const uint64_t stamp = _get_timestamp();

+        if ((stamp / 1000) >= (wake_at / 1000)) {

+            break;

+        }

+        t.tv_sec = (wake_at - stamp) / 1000000;

+        t.tv_usec = (wake_at - stamp) - (uint64_t)t.tv_sec * 1000000;

+    } while (select(0, NULL, NULL, NULL, &t) < 0 && errno == EINTR);

+}

+

+#endif  /* ANDROID_CAMERA_CAMERA_COMMON_H_ */

diff --git a/android/config.c b/android/config.c
index 2c37b03..4f4da46 100644
--- a/android/config.c
+++ b/android/config.c
@@ -17,6 +17,7 @@
 #include <errno.h>
 
 #include "android/config.h"
+#include "android/utils/eintr_wrapper.h"
 #include "android/utils/path.h"
 
 AConfig*
@@ -386,11 +387,7 @@
 
         w->p += avail;
         if (w->p == w->end) {
-            int ret;
-            do {
-                ret = write( w->fd, w->buff, w->p - w->buff );
-            } while (ret < 0 && errno == EINTR);
-            if (ret < 0)
+            if (HANDLE_EINTR(write(w->fd, w->buff, w->p - w->buff)) < 0)
                 break;
             w->p = w->buff;
         }
@@ -401,12 +398,9 @@
 writer_done( Writer*  w )
 {
     if (w->p > w->buff) {
-        int ret;
-        do {
-            ret = write( w->fd, w->buff, w->p - w->buff );
-        } while (ret < 0 && errno == EINTR);
+        HANDLE_EINTR(write(w->fd, w->buff, w->p - w->buff));
     }
-    close( w->fd );
+    IGNORE_EINTR(close( w->fd ));
 }
 
 static void
diff --git a/android/console.c b/android/console.c
index e30e724..ccd0426 100644
--- a/android/console.c
+++ b/android/console.c
@@ -34,6 +34,7 @@
 #include "android/globals.h"
 #include "android/utils/bufprint.h"
 #include "android/utils/debug.h"
+#include "android/utils/eintr_wrapper.h"
 #include "android/utils/stralloc.h"
 #include "android/config/config.h"
 #include "android/tcpdump.h"
@@ -285,9 +286,9 @@
         len = strlen(buff);
 
     while (len > 0) {
-        ret = socket_send( client->sock, buff, len);
+        ret = HANDLE_EINTR(socket_send( client->sock, buff, len));
         if (ret < 0) {
-            if (errno != EINTR && errno != EWOULDBLOCK && errno != EAGAIN)
+            if (errno != EWOULDBLOCK && errno != EAGAIN)
                 return;
         } else {
             buff += ret;
@@ -600,16 +601,11 @@
 
     D(( "control_global_accept: just in (fd=%d)\n", global->listen_fd ));
 
-    for(;;) {
-        fd = socket_accept( global->listen_fd, NULL );
-        if (fd < 0 && errno != EINTR) {
-            D(( "problem in accept: %d: %s\n", errno, errno_str ));
-            perror("accept");
-            return;
-        } else if (fd >= 0) {
-            break;
-        }
-        D(( "relooping in accept()\n" ));
+    fd = HANDLE_EINTR(socket_accept(global->listen_fd, NULL));
+    if (fd < 0) {
+        D(( "problem in accept: %d: %s\n", errno, errno_str ));
+        perror("accept");
+        return;
     }
 
     socket_set_xreuseaddr( fd );
diff --git a/android/main-common.c b/android/main-common.c
index 7db5976..07e7ab0 100644
--- a/android/main-common.c
+++ b/android/main-common.c
@@ -26,6 +26,7 @@
 
 #include "android/avd/util.h"
 #include "android/utils/debug.h"
+#include "android/utils/eintr_wrapper.h"
 #include "android/utils/path.h"
 #include "android/utils/bufprint.h"
 #include "android/utils/dirscanner.h"
@@ -184,9 +185,8 @@
     bufprint_config_file( path, path+sizeof(path), KEYSET_FILE );
 
     /* only write if there is no file here */
-    if ( !path_exists(path) ) {
+    if (!path_exists(path)) {
         int          fd = open( path, O_WRONLY | O_CREAT, 0666 );
-        int          ret;
         const char*  ks = skin_keyset_get_default();
 
 
@@ -196,8 +196,8 @@
             D( "%s: could not create file: %s", __FUNCTION__, strerror(errno) );
             return;
         }
-        CHECKED(ret, write(fd, ks, strlen(ks)));
-        close(fd);
+        HANDLE_EINTR(write(fd, ks, strlen(ks)));
+        IGNORE_EINTR(close(fd));
     }
 }
 
diff --git a/android/protocol/fb-updates-impl.c b/android/protocol/fb-updates-impl.c
index dde79c1..e36c4bf 100644
--- a/android/protocol/fb-updates-impl.c
+++ b/android/protocol/fb-updates-impl.c
@@ -17,6 +17,7 @@
 
 #include "android/utils/system.h"
 #include "android/utils/debug.h"
+#include "android/utils/eintr_wrapper.h"
 #include "android/utils/panic.h"
 #include "android/sync-utils.h"
 #include "android/protocol/core-connection.h"
@@ -113,21 +114,20 @@
     // Read updates while they are immediately available.
     for (;;) {
         // Read next chunk of data.
-        ret = socket_recv(fbi->sock, fbi->reader_buffer + fbi->reader_offset,
-                          fbi->reader_bytes - fbi->reader_offset);
-        if (ret == 0) {
-            /* disconnection ! */
-            fbUpdatesImpl_destroy();
+        ret = HANDLE_EINTR(
+                socket_recv(fbi->sock,
+                            fbi->reader_buffer + fbi->reader_offset,
+                            fbi->reader_bytes - fbi->reader_offset));
+        if (ret < 0 && (errno == EWOULDBLOCK || errno == EAGAIN)) {
+            // Chunk is not avalable at this point. Come back later.
             return;
         }
-        if (ret < 0) {
-            if (errno == EINTR) {
-                /* loop on EINTR */
-                continue;
-            } else if (errno == EWOULDBLOCK || errno == EAGAIN) {
-                // Chunk is not avalable at this point. Come back later.
-                return;
-            }
+        if (ret <= 0) {
+            /* disconnection ! */
+            derror("Unable to receive framebuffer data: %s\n",
+                   ret < 0 ? strerror(errno), "unexpected disconnection");
+            fbUpdatesImpl_destroy();
+            return;
         }
 
         fbi->reader_offset += ret;
diff --git a/android/protocol/ui-commands-impl.c b/android/protocol/ui-commands-impl.c
index 2ceeca1..307e7c7 100644
--- a/android/protocol/ui-commands-impl.c
+++ b/android/protocol/ui-commands-impl.c
@@ -22,6 +22,7 @@
 #include "android/sync-utils.h"
 #include "android/utils/system.h"
 #include "android/utils/debug.h"
+#include "android/utils/eintr_wrapper.h"
 #include "android/utils/panic.h"
 #include "android/protocol/core-connection.h"
 #include "android/protocol/ui-commands-impl.h"
@@ -124,23 +125,23 @@
     // Read requests while they are immediately available.
     for (;;) {
         // Read next chunk of data.
-        status = socket_recv(uicmd->sock,
-                             uicmd->reader_buffer + uicmd->reader_offset,
-                             uicmd->reader_bytes - uicmd->reader_offset);
-        if (status == 0) {
-            /* Disconnection, meaning that the core process got terminated. */
-            fprintf(stderr, "core-ui-control service got disconnected\n");
-            uiCmdImpl_destroy();
+        status = HANDLE_EINTR(
+                socket_recv(uicmd->sock,
+                            uicmd->reader_buffer + uicmd->reader_offset,
+                            uicmd->reader_bytes - uicmd->reader_offset));
+        if (status < 0 && (errno == EWOULDBLOCK || errno == EGAIN) {
+            // Chunk is not avalable at this point. Come back later.
             return;
         }
-        if (status < 0) {
-            if (errno == EINTR) {
-                /* loop on EINTR */
-                continue;
-            } else if (errno == EWOULDBLOCK || errno == EAGAIN) {
-                // Chunk is not avalable at this point. Come back later.
-                return;
-            }
+        if (status <= 0) {
+            /* Disconnection, meaning that the core process got terminated. */
+            fprintf(stderr,
+                    "core-ui-control service got disconnected: %s\n",
+                    status < 0 ?
+                        strerror(errno) :
+                        "unexpected disconnection");
+            uiCmdImpl_destroy();
+            return;
         }
 
         uicmd->reader_offset += status;
diff --git a/android/snapshot.c b/android/snapshot.c
index 7ab135f..8c10341 100644
--- a/android/snapshot.c
+++ b/android/snapshot.c
@@ -35,6 +35,7 @@
 
 #include "qemu/bswap.h"
 #include "android/utils/debug.h"
+#include "android/utils/eintr_wrapper.h"
 #include "android/utils/system.h"
 #include "android/snapshot.h"
 
@@ -50,17 +51,11 @@
 static int
 read_or_die(int fd, void *buf, size_t nbyte)
 {
-    int ret = 0;
-    do {
-        ret = read(fd, buf, nbyte);
-    }
-    while(ret < 0 && errno == EINTR);
-
+    int ret = HANDLE_EINTR(read(fd, buf, nbyte));
     if (ret < 0) {
         derror("read failed: %s", strerror(errno));
         exit(1);
     }
-
     return ret;
 }
 
diff --git a/android/sockets.c b/android/sockets.c
index fec87bf..697501e 100644
--- a/android/sockets.c
+++ b/android/sockets.c
@@ -23,6 +23,7 @@
 #include <string.h>
 #include "android/utils/path.h"
 #include "android/utils/debug.h"
+#include "android/utils/eintr_wrapper.h"
 #include "android/utils/misc.h"
 #include "android/utils/system.h"
 
@@ -59,7 +60,7 @@
 #  define  QSOCKET_CALL(_ret,_cmd)   \
     do { \
         errno = 0; \
-        do { _ret = (_cmd); } while ( _ret < 0 && errno == EINTR ); \
+        _ret = HANDLE_EINTR(_cmd); \
     } while (0);
 #endif
 
@@ -1096,10 +1097,11 @@
         int  opt  = -1;
 #endif
         socklen_t  optlen = sizeof(opt);
-        ret = getsockopt(fd, domain, option, (char*)&opt, &optlen);
+        ret = HANDLE_EINTR(
+                getsockopt(fd, domain, option, (char*)&opt, &optlen));
         if (ret == 0)
             return (int)opt;
-        if (errno != EINTR)
+        else
             return defaut;
     }
 #undef OPT_CAST
@@ -1263,7 +1265,7 @@
     int  old_errno = errno;
 
     shutdown( fd, SHUT_RDWR );
-    close( fd );
+    IGNORE_EINTR(close( fd ));
 
     errno = old_errno;
 }
@@ -1405,9 +1407,7 @@
 
     sock_address_init_unix( &addr, name );
 
-    do {
-        ret = unlink( name );
-    } while (ret < 0 && errno == EINTR);
+    HANDLE_EINTR(unlink(name));
 
     ret = socket_bind_server( s, &addr, type );
 
diff --git a/android/sync-utils.c b/android/sync-utils.c
index 4f2fd81..365d475 100644
--- a/android/sync-utils.c
+++ b/android/sync-utils.c
@@ -79,7 +79,7 @@
                 iolooper_free(looper);
                 return NULL;
             }
-        } else if (errno != EINTR) {
+        } else {
             return NULL;
         }
     }
@@ -184,9 +184,7 @@
             D("%s: Internal error, iolooper_is_read() not set!", __FUNCTION__);
             return -1;
         }
-        do {
-            ret = socket_recv(ssocket->fd, buf, size);
-        } while( ret < 0 && errno == EINTR);
+        ret = socket_recv(ssocket->fd, buf, size);
     } else if (ret == 0) {
         // Timed out
         errno = ETIMEDOUT;
@@ -229,10 +227,7 @@
             return -1;
         }
 
-        do {
-            ret = socket_send(ssocket->fd, (const char*)buf + written, size - written);
-        } while( ret < 0 && errno == EINTR);
-
+        ret = socket_send(ssocket->fd, (const char*)buf + written, size - written);
         if (ret > 0) {
             written += ret;
         } else if (ret < 0) {
diff --git a/android/utils/eintr_wrapper.c b/android/utils/eintr_wrapper.c
new file mode 100644
index 0000000..2562e5c
--- /dev/null
+++ b/android/utils/eintr_wrapper.c
@@ -0,0 +1,30 @@
+// Copyright 2014 The Android Open Source Project
+//
+// This software is licensed under the terms of the GNU General Public
+// License version 2, as published by the Free Software Foundation, and
+// may be copied, distributed, and modified under those terms.
+//
+// This program 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 General Public License for more details.
+
+#include "android/utils/eintr_wrapper.h"
+
+#include "android/utils/panic.h"
+
+#ifndef _WIN32
+void android_eintr_wrapper_fatal(const char* file,
+                                 long lineno,
+                                 const char* function,
+                                 const char* call) {
+    android_panic(
+            "%s:%ld:%s%s System call looped around EINTR %d times: %s\n",
+            file,
+            lineno,
+            function ? function : "",
+            function ? ":" : "",
+            MAX_EINTR_LOOP_COUNT,
+            call);
+}
+#endif  // !_WIN32
\ No newline at end of file
diff --git a/android/utils/eintr_wrapper.h b/android/utils/eintr_wrapper.h
new file mode 100644
index 0000000..4a595d1
--- /dev/null
+++ b/android/utils/eintr_wrapper.h
@@ -0,0 +1,120 @@
+// Copyright 2014 The Android Open Source Project
+//
+// This software is licensed under the terms of the GNU General Public
+// License version 2, as published by the Free Software Foundation, and
+// may be copied, distributed, and modified under those terms.
+//
+// This program 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 General Public License for more details.
+#ifndef ANDROID_UTILS_EINTR_WRAPPER_H
+#define ANDROID_UTILS_EINTR_WRAPPER_H
+
+#include <errno.h>
+
+#include "android/utils/compiler.h"
+
+ANDROID_BEGIN_HEADER
+
+// Set EINTR_WRAPPER_DEBUG to 1 to force the debug version of HANDLE_EINTR
+// which will call android_eintr_wrapper_fatal() is the system call loops
+// too many times, or 0 to get it to loop indefinitly.
+// Mostly used for unit testing.
+// If the macro is undefined, auto-detect the value based on NDEBUG.
+#if !defined(EINTR_WRAPPER_DEBUG)
+#  ifdef NDEBUG
+#    define EINTER_WRAPPER_DEBUG 0
+#  else
+#    define EINTR_WRAPPER_DEBUG 1
+#  endif
+#endif
+
+// HANDLE_EINTR() is a macro used to handle EINTR return values when
+// calling system calls like open() or read() on Posix systems.
+//
+// By default, this will loop indefinitly, retrying the call until
+// the result is no longer -1/EINTR, except in debug mode, where a
+// loop counter is actually used and to provoke a fatal error if there
+// are too many loops.
+//
+// Usage example:
+//     int ret = HANDLE_EINTR(open("/some/file/path", O_RDONLY));
+//
+// IMPORTANT: Do not use with the close() system call (use IGNORE_EINTR()
+// instead).
+//
+// - On Linux, the file descriptor is always already closed when this
+//   function returns -1/EINTR, and calling it again with the same
+//   parameters risks closing another file descriptor open by another
+//   thread in parallel!
+//
+// - On OS X, whether the file descriptor is closed or not is pretty
+//   much random! It's better to leave the descriptor open than risk
+//   closing another one by mistake :(
+//
+#ifdef _WIN32
+#  define HANDLE_EINTR(x)  (x)
+#elif EINTR_WRAPPER_DEBUG == 0
+#  define HANDLE_EINTR(x) \
+    __extension__ ({ \
+        __typeof__(x) eintr_wrapper_result; \
+        do { \
+            eintr_wrapper_result = (x); \
+        } while (eintr_wrapper_result < 0 && errno == EINTR); \
+        eintr_wrapper_result; \
+    })
+#else  // !_WIN32 && EINTR_WRAPPER_DEBUG
+
+#  define MAX_EINTR_LOOP_COUNT  100
+
+#  define HANDLE_EINTR(x) \
+    __extension__ ({ \
+        __typeof__(x) eintr_wrapper_result; \
+        int eintr_wrapper_loop_count = 0; \
+        for (;;) { \
+            eintr_wrapper_result = (x); \
+            if (eintr_wrapper_result != -1 || errno != EINTR) \
+                break; \
+            if (++eintr_wrapper_loop_count >= MAX_EINTR_LOOP_COUNT) { \
+                android_eintr_wrapper_fatal( \
+                        __FILE__,__LINE__,__PRETTY_FUNCTION__,#x); \
+            } \
+        }; \
+        eintr_wrapper_result; \
+    })
+#endif  // !_WIN32 && EINTR_WRAPPER_DEBUG
+
+// IGNORE_EINTR() is a macro used to perform a system call and ignore
+// an EINTR result, i.e. it will return 0 instead of -1 if this occurs.
+// This is mostly used with the close() system call, as described
+// in the HANDLE_EINTR() documentation.
+#ifdef _WIN32
+#  define IGNORE_EINTR(x)  (x)
+#else
+#  define IGNORE_EINTR(x) \
+    __extension__ ({ \
+        __typeof__(x) eintr_wrapper_result = (x); \
+        if (eintr_wrapper_result == -1 && errno == EINTR) \
+            eintr_wrapper_result = 0; \
+        eintr_wrapper_result; \
+    })
+#endif
+
+#ifndef _WIN32
+// This function is called in debug mode only when a system call wrapped
+// by HANDLE_EINTR() failed more than MAX_EINTR_LOOP_COUNT times.
+// |file| is the source file location.
+// |lineno| is the line number in the source file.
+// |function| is the name of the function, or NULL if not available.
+// |call| is a string describing the system call that failed.
+void __attribute__((noreturn)) android_eintr_wrapper_fatal(
+        const char* file,
+        long lineno,
+        const char* function,
+        const char* call);
+#endif  // !_WIN32
+
+ANDROID_END_HEADER
+
+#endif  // ANDROID_UTILS_EINTR_WRAPPER_H
diff --git a/android/utils/eintr_wrapper_unittest.cpp b/android/utils/eintr_wrapper_unittest.cpp
new file mode 100644
index 0000000..0236abf
--- /dev/null
+++ b/android/utils/eintr_wrapper_unittest.cpp
@@ -0,0 +1,121 @@
+// Copyright 2014 The Android Open Source Project
+//
+// This software is licensed under the terms of the GNU General Public
+// License version 2, as published by the Free Software Foundation, and
+// may be copied, distributed, and modified under those terms.
+//
+// This program 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 General Public License for more details.
+
+// Forces debug mode
+#define EINTR_WRAPPER_DEBUG 1
+
+#include "android/utils/eintr_wrapper.h"
+
+#include <stdarg.h>
+#include <setjmp.h>
+
+#include "android/utils/panic.h"
+
+#include <gtest/gtest.h>
+
+// Loop counter used by several functions below.
+static int loop_count = 0;
+
+// This function returns the first time it is called, or -1/EINVAL
+// otherwise.
+static int return_einval_after_first_call(void) {
+    if (++loop_count == 1)
+        return 0;
+
+    errno = EINVAL;
+    return -1;
+}
+
+TEST(eintr_wrapper,NoLoopOnSuccess) {
+    loop_count = 0;
+    EXPECT_EQ(0, HANDLE_EINTR(return_einval_after_first_call()));
+    EXPECT_EQ(1, loop_count);
+}
+
+TEST(eintr_wrapper,NoLoopOnRegularError) {
+    loop_count = 0;
+    EXPECT_EQ(0, HANDLE_EINTR(return_einval_after_first_call()));
+    EXPECT_EQ(-1, HANDLE_EINTR(return_einval_after_first_call()));
+    EXPECT_EQ(EINVAL, errno);
+    EXPECT_EQ(2, loop_count);
+}
+
+static int always_return_eintr(void) {
+    loop_count++;
+#ifdef _WIN32
+    // Win32 cannot generate EINTR.
+    return 0;
+#else
+    errno = EINTR;
+    return -1;
+#endif
+}
+
+TEST(eintr_wrapper,IgnoreEintr) {
+    loop_count = 0;
+    EXPECT_EQ(0, IGNORE_EINTR(always_return_eintr()));
+    EXPECT_EQ(1, loop_count);
+}
+
+#ifndef _WIN32
+
+// This function loops 10 times around |loop_count|, while returning
+// -1/errno.
+static int loop_eintr_10(void) {
+    if (++loop_count < 10) {
+        errno = EINTR;
+        return -1;
+    }
+    return 0;
+}
+
+TEST(eintr_wrapper,LoopOnEintr) {
+    loop_count = 0;
+    EXPECT_EQ(0, HANDLE_EINTR(loop_eintr_10()));
+    EXPECT_EQ(10, loop_count);
+}
+
+// Implementation of a custom panic function used to detect that
+// HANDLE_EINTR() called panic after too many loop iterations.
+// Uses setjmp()/longjmp() since the panic handler must be
+// __attribute__((noreturn)).
+static jmp_buf panic_jumper;
+static bool panic_called = false;
+
+static void __attribute__((noreturn))
+        my_panic_handler(const char*, va_list);
+
+static void my_panic_handler(const char* fmt, va_list args) {
+    panic_called = true;
+    longjmp(panic_jumper, 1);
+}
+
+static int loop_eintr_200(void) {
+    if (++loop_count < 200) {
+        errno = EINTR;
+        return -1;
+    }
+    return 0;
+}
+
+TEST(eintr_wrapper,PanicOnTooManyLoops) {
+    loop_count = 0;
+    android_panic_registerHandler(my_panic_handler);
+    if (setjmp(panic_jumper) == 0) {
+        HANDLE_EINTR(loop_eintr_200());
+        ASSERT_TRUE(0) << "HANDLE_EINTR() didn't panic!";
+    } else {
+        EXPECT_EQ(true, panic_called);
+        EXPECT_EQ(MAX_EINTR_LOOP_COUNT, loop_count);
+    }
+}
+
+#endif  // !_WIN32
diff --git a/android/utils/filelock.c b/android/utils/filelock.c
index a8b18da..8baffe4 100644
--- a/android/utils/filelock.c
+++ b/android/utils/filelock.c
@@ -10,6 +10,7 @@
 ** GNU General Public License for more details.
 */
 
+#include "android/utils/eintr_wrapper.h"
 #include "android/utils/filelock.h"
 #include "android/utils/path.h"
 #include <stdio.h>
@@ -30,14 +31,6 @@
 
 #define  D(...)  ((void)0)
 
-#ifndef CHECKED
-#  ifdef _WIN32
-#    define   CHECKED(ret, call)    (ret) = (call)
-#  else
-#    define   CHECKED(ret, call)    do { (ret) = (call); } while ((ret) < 0 && errno == EINTR)
-#  endif
-#endif
-
 /** FILE LOCKS SUPPORT
  **
  ** a FileLock is useful to prevent several emulator instances from using the same
@@ -241,7 +234,7 @@
     close( temp_fd );
     temp_fd = -1;
 
-    CHECKED(rc, lstat( lock->temp, &st_temp ));
+    rc = HANDLE_EINTR(lstat( lock->temp, &st_temp ));
     if (rc < 0) {
         D( "can't properly stat our locking temp file '%s'", lock->temp );
         goto Fail;
@@ -264,16 +257,16 @@
         _sleep += 200000;
 
         /* the return value of link() is buggy on NFS */
-        CHECKED(rc, link( lock->temp, lock->lock ));
+        rc = HANDLE_EINTR(link( lock->temp, lock->lock ));
 
-        CHECKED(rc, lstat( lock->lock, &st_lock ));
+        rc = HANDLE_EINTR(lstat( lock->lock, &st_lock ));
         if (rc == 0 &&
             st_temp.st_rdev == st_lock.st_rdev &&
             st_temp.st_ino  == st_lock.st_ino  )
         {
             /* SUCCESS */
             lock->locked = 1;
-            CHECKED(rc, unlink( lock->temp ));
+            rc = HANDLE_EINTR(unlink( lock->temp ));
             return 0;
         }
 
@@ -287,26 +280,26 @@
             int     stale = 2;  /* means don't know */
             struct stat  st;
 
-            CHECKED(rc, time( &now));
+            rc = HANDLE_EINTR(time( &now));
             st.st_mtime = now - 120;
 
-            CHECKED(lockfd, open( lock->lock,O_RDONLY ));
+            lockfd = HANDLE_EINTR(open( lock->lock,O_RDONLY ));
             if ( lockfd >= 0 ) {
                 int  len;
 
-                CHECKED(len, read( lockfd, buf, sizeof(buf)-1 ));
+                len = HANDLE_EINTR(read( lockfd, buf, sizeof(buf)-1 ));
                 buf[len] = 0;
                 lockpid = atoi(buf);
 
-                CHECKED(rc, fstat( lockfd, &st ));
+                rc = HANDLE_EINTR(fstat( lockfd, &st ));
                 if (rc == 0)
                   now = st.st_atime;
 
-                CHECKED(rc, close(lockfd));
+                IGNORE_EINTR(close(lockfd));
             }
             /* if there is a PID, check that it is still alive */
             if (lockpid > 0) {
-                CHECKED(rc, kill( lockpid, 0 ));
+                rc = HANDLE_EINTR(kill( lockpid, 0 ));
                 if (rc == 0 || errno == EPERM) {
                     stale = 0;
                 } else if (rc < 0 && errno == ESRCH) {
@@ -320,7 +313,7 @@
 
             if (stale) {
                 D( "removing stale lockfile '%s'", lock->lock );
-                CHECKED(rc, unlink( lock->lock ));
+                rc = HANDLE_EINTR(unlink( lock->lock ));
                 _sleep = 0;
                 tries++;
             }
@@ -333,15 +326,15 @@
         fclose(f);
 
     if (temp_fd >= 0) {
-        close(temp_fd);
+        IGNORE_EINTR(close(temp_fd));
     }
 
     if (lock_fd >= 0) {
-        close(lock_fd);
+        IGNORE_EINTR(close(lock_fd));
     }
 
-    unlink( lock->lock );
-    unlink( lock->temp );
+    HANDLE_EINTR(unlink(lock->lock));
+    HANDLE_EINTR(unlink(lock->temp));
     return -1;
 #endif
 }
diff --git a/android/utils/mapfile.c b/android/utils/mapfile.c
index 61b57c4..84eda44 100644
--- a/android/utils/mapfile.c
+++ b/android/utils/mapfile.c
@@ -15,6 +15,8 @@
  * file I/O.
  */
 
+#include "android/utils/mapfile.h"
+
 #include "stddef.h"
 #include "sys/types.h"
 #include "errno.h"
@@ -27,7 +29,7 @@
 #include <fcntl.h>
 #include <unistd.h>
 
-#include "mapfile.h"
+#include "android/utils/eintr_wrapper.h"
 
 MapFile*
 mapfile_open(const char* path, int oflag, int share_mode)
@@ -120,11 +122,7 @@
     }
     return ret_bytes;
 #else   // WIN32
-    ssize_t ret;
-    do {
-        ret = read((int)(ptrdiff_t)handle, buf, nbyte);
-    } while (ret < 0 && errno == EINTR);
-    return ret;
+    return HANDLE_EINTR(read((int)(ptrdiff_t)handle, buf, nbyte));
 #endif  // WIN32
 }
 
diff --git a/android/utils/mapfile.h b/android/utils/mapfile.h
index 18f8845..b66e1b8 100644
--- a/android/utils/mapfile.h
+++ b/android/utils/mapfile.h
@@ -18,9 +18,12 @@
 #ifndef _ANDROID_UTILS_FILEIO_H
 #define _ANDROID_UTILS_FILEIO_H
 
-#ifdef __cplusplus
-extern "C" {
-#endif
+#include "android/utils/compiler.h"
+
+#include <stddef.h>
+#include <unistd.h>
+
+ANDROID_BEGIN_HEADER
 
 typedef struct MapFile MapFile;
 
@@ -126,8 +129,6 @@
  */
 extern int mapfile_unmap(void* mapped_at, size_t len);
 
-#ifdef __cplusplus
-}   /* end of extern "C" */
-#endif
+ANDROID_END_HEADER
 
 #endif  // _ANDROID_UTILS_FILEIO_H
diff --git a/android/utils/panic.h b/android/utils/panic.h
index e141ef1..d26ddc1 100644
--- a/android/utils/panic.h
+++ b/android/utils/panic.h
@@ -14,6 +14,10 @@
 
 #include <stdarg.h>
 
+#include "android/utils/compiler.h"
+
+ANDROID_BEGIN_HEADER
+
 /* Print formatted panic message and halts the process */
 void __attribute__((noreturn)) android_panic ( const char*  fmt, ... );
 
@@ -25,9 +29,9 @@
 
 typedef void (*APanicHandlerFunc)(const char*, va_list) __attribute__((noreturn));
 
-#ifdef ACONFIG_UNIT_TEST
 /* Register a new panic handler. This should only be used for unit-testing */
 void android_panic_registerHandler( APanicHandlerFunc  handler );
-#endif /* ACONFIG_UNIT_TEST */
+
+ANDROID_END_HEADER
 
 #endif /* ANDROID_UTILS_PANIC_H */
diff --git a/android/utils/path.c b/android/utils/path.c
index 95c9c2e..0847787 100644
--- a/android/utils/path.c
+++ b/android/utils/path.c
@@ -9,6 +9,8 @@
 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 ** GNU General Public License for more details.
 */
+#include "android/utils/debug.h"
+#include "android/utils/eintr_wrapper.h"
 #include "android/utils/path.h"
 
 #include <stdio.h>
@@ -34,17 +36,8 @@
 #include <signal.h>
 #endif
 
-#include "android/utils/debug.h"
 #define  D(...)  VERBOSE_PRINT(init,__VA_ARGS__)
 
-#ifndef CHECKED
-#  ifdef _WIN32
-#    define   CHECKED(ret, call)    (ret) = (call)
-#  else
-#    define   CHECKED(ret, call)    do { (ret) = (call); } while ((ret) < 0 && errno == EINTR)
-#  endif
-#endif
-
 /** PATH HANDLING ROUTINES
  **
  **  path_parent() can be used to return the n-level parent of a given directory
@@ -218,10 +211,10 @@
 ABool
 path_exists( const char*  path )
 {
-    int  ret;
-    if (path == NULL)
+    if (!path)
         return 0;
-    CHECKED(ret, access(path, F_OK));
+
+    int ret = HANDLE_EINTR(access(path, F_OK));
     return (ret == 0) || (errno != ENOENT);
 }
 
@@ -229,12 +222,11 @@
 ABool
 path_is_regular( const char*  path )
 {
-    int          ret;
-    struct stat  st;
-
     if (path == NULL)
         return 0;
-    CHECKED(ret, stat(path, &st));
+
+    struct stat  st;
+    int ret = HANDLE_EINTR(stat(path, &st));
     if (ret < 0)
         return 0;
 
@@ -246,12 +238,11 @@
 ABool
 path_is_dir( const char*  path )
 {
-    int          ret;
-    struct stat  st;
-
-    if (path == NULL)
+    if (!path)
         return 0;
-    CHECKED(ret, stat(path, &st));
+
+    struct stat  st;
+    int ret = HANDLE_EINTR(stat(path, &st));
     if (ret < 0)
         return 0;
 
@@ -262,31 +253,28 @@
 ABool
 path_can_read( const char*  path )
 {
-    int  ret;
-    if (path == NULL)
+    if (!path)
         return 0;
-    CHECKED(ret, access(path, R_OK));
-    return (ret == 0);
+
+    return HANDLE_EINTR(access(path, R_OK)) == 0;
 }
 
 ABool
 path_can_write( const char*  path )
 {
-    int  ret;
-    if (path == NULL)
+    if (!path)
         return 0;
-    CHECKED(ret, access(path, R_OK));
-    return (ret == 0);
+
+    return HANDLE_EINTR(access(path, W_OK)) == 0;
 }
 
 ABool
 path_can_exec( const char* path )
 {
-    int  ret;
-    if (path == NULL)
+    if (!path)
         return 0;
-    CHECKED(ret, access(path, X_OK));
-    return (ret == 0);
+
+    return HANDLE_EINTR(access(path, X_OK)) == 0;
 }
 
 /* try to make a directory. returns 0 on success, -1 on failure
@@ -298,9 +286,7 @@
     (void)mode;
     return _mkdir(path);
 #else
-    int  ret;
-    CHECKED(ret, mkdir(path, mode));
-    return ret;
+    return HANDLE_EINTR(mkdir(path, mode));
 #endif
 }
 
@@ -408,10 +394,8 @@
     CloseHandle(file);
     return 0;
 #else
-    int    ret;
     struct stat  st;
-
-    CHECKED(ret, stat(path, &st));
+    int ret = HANDLE_EINTR(stat(path, &st));
     if (ret == 0) {
         *psize = (uint64_t) st.st_size;
     }
diff --git a/android/utils/system.h b/android/utils/system.h
index 978f11c..4f4677d 100644
--- a/android/utils/system.h
+++ b/android/utils/system.h
@@ -109,19 +109,6 @@
 #  define  strcasecmp  stricmp
 #endif
 
-/** EINTR HANDLING
- **
- ** since QEMU uses SIGALRM pretty extensively, having a system call returning
- ** EINTR on Unix happens very frequently. provide a simple macro to guard against
- ** this.
- **/
-
-#ifdef _WIN32
-#  define   CHECKED(ret, call)    (ret) = (call)
-#else
-#  define   CHECKED(ret, call)    do { (ret) = (call); } while ((ret) < 0 && errno == EINTR)
-#endif
-
 /** SIGNAL HANDLING
  **
  ** the following can be used to block SIGALRM for a given period of time.
diff --git a/android/utils/timezone.c b/android/utils/timezone.c
index 1b99917..2ca14dc 100644
--- a/android/utils/timezone.c
+++ b/android/utils/timezone.c
@@ -10,6 +10,7 @@
 ** GNU General Public License for more details.
 */
 #include "android/utils/debug.h"
+#include "android/utils/eintr_wrapper.h"
 #include "android/utils/timezone.h"
 #include "android/utils/bufprint.h"
 #include "android/android.h"
@@ -207,10 +208,10 @@
             char  temp[2];
             int   ret;
 
-            do { ret = read(fd1, &temp[0], 1); } while (ret < 0 && errno == EINTR);
+            ret = HANDLE_EINTR(read(fd1, &temp[0], 1));
             if (ret < 0) break;
 
-            do { ret = read(fd2, &temp[1], 1); } while (ret < 0 && errno == EINTR);
+            ret = HANDLE_EINTR(read(fd2, &temp[1], 1));
             if (ret < 0) break;
 
             if (temp[0] != temp[1])