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])