added direct syscalls for ARM
diff --git a/aos/linux_code/ipc_lib/aos_sync.c b/aos/linux_code/ipc_lib/aos_sync.c
index a607001..2245436 100644
--- a/aos/linux_code/ipc_lib/aos_sync.c
+++ b/aos/linux_code/ipc_lib/aos_sync.c
@@ -43,18 +43,78 @@
// 0 = unset
// 1 = set
-static inline int sys_futex(mutex *addr1, int op, int val1,
- const struct timespec *timeout, void *addr2, int val3) {
- return syscall(SYS_futex, addr1, op, val1, timeout, addr2, val3);
+// These sys_futex_* functions are wrappers around syscall(SYS_futex). They each
+// take a specific set of arguments for a given futex operation. They return the
+// result or a negated errno value. -1..-4095 mean errors and not successful
+// results, which is guaranteed by the kernel.
+// They each have optimized versions for ARM EABI (the syscall interface is
+// different for non-EABI ARM, so that is the right thing to test for) that
+// don't go through syscall(2) or errno.
+
+static inline int sys_futex_wait(mutex *addr1, int val1,
+ const struct timespec *timeout) {
+#ifdef __ARM_EABI__
+ register mutex *addr1_reg __asm__("r0") = addr1;
+ register int op_reg __asm__("r1") = FUTEX_WAIT;
+ register int val1_reg __asm__("r2") = val1;
+ register const struct timespec *timeout_reg __asm__("r3") = timeout;
+ register int syscall_number __asm__("r7") = SYS_futex;
+ register int result __asm__("r0");
+ __asm__ volatile("swi #0"
+ : "=r"(result)
+ : "r"(addr1_reg), "r"(op_reg), "r"(val1_reg),
+ "r"(timeout_reg), "r"(syscall_number)
+ : "memory");
+ return result;
+#else
+ const int r = syscall(SYS_futex, addr1, FUTEX_WAIT, val1, timeout);
+ if (r == -1) return -errno;
+ return r;
+#endif
}
-static inline int sys_futex_requeue(mutex *addr1, int op, int num_wake,
+
+static inline int sys_futex_wake(mutex *addr1, int val1) {
+#ifdef __ARM_EABI__
+ register mutex *addr1_reg __asm__("r0") = addr1;
+ register int op_reg __asm__("r1") = FUTEX_WAKE;
+ register int val1_reg __asm__("r2") = val1;
+ register int syscall_number __asm__("r7") = SYS_futex;
+ register int result __asm__("r0");
+ __asm__ volatile("swi #0"
+ : "=r"(result)
+ : "r"(addr1_reg), "r"(op_reg), "r"(val1_reg),
+ "r"(syscall_number)
+ : "memory");
+ return result;
+#else
+ const int r = syscall(SYS_futex, addr1, FUTEX_WAKE, val1);
+ if (r == -1) return -errno;
+ return r;
+#endif
+}
+
+static inline int sys_futex_requeue(mutex *addr1, int num_wake,
int num_requeue, mutex *m) {
- return syscall(SYS_futex, addr1, op, num_wake, num_requeue, m);
-}
-static inline int sys_futex_op(mutex *addr1, int op, int num_waiters1,
- int num_waiters2, mutex *addr2, int op_args_etc) {
- return syscall(SYS_futex, addr1, op, num_waiters1,
- num_waiters2, addr2, op_args_etc);
+#ifdef __ARM_EABI__
+ register mutex *addr1_reg __asm__("r0") = addr1;
+ register int op_reg __asm__("r1") = FUTEX_REQUEUE;
+ register int num_wake_reg __asm__("r2") = num_wake;
+ register int num_requeue_reg __asm__("r3") = num_requeue;
+ register mutex *m_reg __asm__("r4") = m;
+ register int syscall_number __asm__("r7") = SYS_futex;
+ register int result __asm__("r0");
+ __asm__ volatile("swi #0"
+ : "=r"(result)
+ : "r"(addr1_reg), "r"(op_reg), "r"(num_wake_reg),
+ "r"(num_requeue_reg), "r"(m_reg), "r"(syscall_number)
+ : "memory");
+ return result;
+#else
+ const int r =
+ syscall(SYS_futex, addr1, FUTEX_REQUEUE, num_wake, num_requeue, m);
+ if (r == -1) return -errno;
+ return r;
+#endif
}
static inline int mutex_get(mutex *m, uint8_t signals_fail, const
@@ -66,11 +126,12 @@
if (c == 1) c = xchg(m, 2);
while (c) {
/* Wait in the kernel */
- if (sys_futex(m, FUTEX_WAIT, 2, timeout, NULL, 0) == -1) {
- if (signals_fail && errno == EINTR) {
+ const int ret = sys_futex_wait(m, 2, timeout);
+ if (ret != 0) {
+ if (signals_fail && ret == -EINTR) {
return 1;
}
- if (timeout != NULL && errno == ETIMEDOUT) {
+ if (timeout != NULL && ret == -ETIMEDOUT) {
return 2;
}
}
@@ -99,15 +160,17 @@
case 1:
//printf("mutex_unlock return(%p) => %d \n",m,*m);
break;
- case 2:
- if (sys_futex(m, FUTEX_WAKE, 1, NULL, NULL, 0) == -1) {
+ case 2: {
+ const int ret = sys_futex_wake(m, 1);
+ if (ret < 0) {
fprintf(stderr, "sync: waking 1 from %p failed with %d: %s\n",
- m, errno, strerror(errno));
+ m, -ret, strerror(-ret));
printf("see stderr\n");
abort();
} else {
break;
}
+ }
default:
fprintf(stderr, "sync: got a garbage value from mutex %p. aborting\n",
m);
@@ -126,10 +189,12 @@
if (*m) {
return 0;
}
- if (sys_futex(m, FUTEX_WAIT, 0, NULL, NULL, 0) == -1) {
- if (errno == EINTR) {
+ const int ret = sys_futex_wait(m, 0, NULL);
+ if (ret != 0) {
+ if (ret == -EINTR) {
return 1;
- } else if (errno != EWOULDBLOCK) {
+ } else if (ret != -EWOULDBLOCK) {
+ errno = -ret;
return -1;
}
}
@@ -137,7 +202,13 @@
}
int futex_set_value(mutex *m, mutex value) {
xchg(m, value);
- return sys_futex(m, FUTEX_WAKE, INT_MAX, NULL, NULL, 0);
+ const int r = sys_futex_wake(m, INT_MAX - 4096);
+ if (__builtin_expect((unsigned int)r > (unsigned int)-4096, 0)) {
+ errno = -r;
+ return -1;
+ } else {
+ return r;
+ }
}
int futex_set(mutex *m) {
return futex_set_value(m, 1);
@@ -154,15 +225,16 @@
while (1) {
// Wait in the kernel iff the value of it doesn't change (ie somebody else
// does a wake) from before we unlocked the mutex.
- if (sys_futex(c, FUTEX_WAIT, wait_start, NULL, NULL, 0) == -1) {
+ const int ret = sys_futex_wait(c, wait_start, NULL);
+ if (ret != 0) {
// If it failed for some reason other than somebody else doing a wake
// before we actually made it to sleep.
if (__builtin_expect(*c == wait_start, 0)) {
// Try again if it was because of a signal.
- if (errno == EINTR) continue;
+ if (ret == -EINTR) continue;
fprintf(stderr, "FUTEX_WAIT(%p, %"PRIu32", NULL, NULL, 0) failed"
" with %d: %s\n",
- c, wait_start, errno, strerror(errno));
+ c, wait_start, -ret, strerror(-ret));
printf("see stderr\n");
abort();
}
@@ -174,13 +246,14 @@
// the person waking us from the above wait (changed to be on the mutex
// instead of the condition) will have just set it to 0.
while (xchg(m, 2) != 0) {
- if (sys_futex(m, FUTEX_WAIT, 2, NULL, NULL, 0) == -1) {
+ const int ret = sys_futex_wait(m, 2, NULL);
+ if (ret != 0) {
// Try again if it was because of a signal or somebody else unlocked it
// before we went to sleep.
- if (errno == EINTR || errno == EWOULDBLOCK) continue;
+ if (ret == -EINTR || ret == -EWOULDBLOCK) continue;
fprintf(stderr, "sync: FUTEX_WAIT(%p, 2, NULL, NULL, 0)"
" failed with %d: %s\n",
- m, errno, strerror(errno));
+ m, -ret, strerror(-ret));
printf("see stderr\n");
abort();
}
@@ -195,10 +268,11 @@
// instead.
__sync_fetch_and_add(c, 1);
// Wake at most 1 person who is waiting in the kernel.
- if (sys_futex(c, FUTEX_WAKE, 1, NULL, NULL, 0) == -1) {
+ const int ret = sys_futex_wake(c, 1);
+ if (ret < 0) {
fprintf(stderr, "sync: FUTEX_WAKE(%p, 1, NULL, NULL, 0)"
" failed with %d: %s\n",
- c, errno, strerror(errno));
+ c, -ret, strerror(-ret));
printf("see stderr\n");
abort();
}
@@ -209,10 +283,11 @@
// Wake at most 1 waiter and requeue the rest.
// Everybody else is going to have to wait for the 1st person to take the
// mutex anyways.
- if (sys_futex_requeue(c, FUTEX_REQUEUE, 1, INT_MAX, m) == -1) {
+ const int ret = sys_futex_requeue(c, 1, INT_MAX, m);
+ if (ret < 0) {
fprintf(stderr, "sync: FUTEX_REQUEUE(%p, 1, INT_MAX, %p, 0)"
" failed with %d: %s\n",
- c, m, errno, strerror(errno));
+ c, m, -ret, strerror(-ret));
printf("see stderr\n");
abort();
}