[LibOS] Emulate pause() by sleeping for a very long time

Before, pause() was emulated by sleeping for 1s in a loop until
signal interrupted it. If signal arrived in-between these invocations
then pause() could never return. Also, pause() incorrectly returned 0
instead of -1 and errno=EINTR.

This patch emulates pause() by sleeping for a very long time (years).
Also, it correctly returns EINTR.
This commit is contained in:
Isaku Yamahata
2019-04-30 17:07:51 -07:00
committed by Dmitrii Kuvaiskii
parent 382a1ec394
commit f72cd48ee5
5 changed files with 60 additions and 23 deletions
+3 -10
View File
@@ -34,18 +34,11 @@
#include <errno.h>
#define SHIM_DEFAULT_SLEEP 1000
int shim_do_pause (void)
{
while (1) {
unsigned long ret = DkThreadDelayExecution(SHIM_DEFAULT_SLEEP);
if (!ret)
break;
}
return 0;
/* ~0ULL micro sec ~= 805675 years */
DkThreadDelayExecution(~((PAL_NUM)0));
return -EINTR;
}
int shim_do_nanosleep (const struct __kernel_timespec * rqtp,
+27
View File
@@ -0,0 +1,27 @@
#include <assert.h>
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void handler(int signal)
{
printf("hello world\n");
}
int main(int argc, char ** argv)
{
if (signal(SIGALRM, &handler) < 0)
return EXIT_FAILURE;
if (alarm(1) < 0)
return EXIT_FAILURE;
int ret = pause();
assert(ret == -1);
assert(errno == EINTR);
printf("good bye\n");
return 0;
}
+9 -5
View File
@@ -85,11 +85,15 @@ int _DkThreadDelayExecution (unsigned long * duration)
struct timespec sleeptime;
struct timespec remainingtime;
long sec = (unsigned long) *duration / 1000000;
long microsec = (unsigned long) *duration - (sec * 1000000);
sleeptime.tv_sec = sec;
sleeptime.tv_nsec = microsec * 1000;
#define VERY_LONG_TIME_IN_US (1000000L * 60 * 60 * 24 * 365 * 128)
if (*duration > VERY_LONG_TIME_IN_US) {
/* avoid overflow with time_t */
sleeptime.tv_sec = VERY_LONG_TIME_IN_US / 1000000;
sleeptime.tv_nsec = 0;
} else {
sleeptime.tv_sec = *duration / 1000000;
sleeptime.tv_nsec = (*duration - sleeptime.tv_sec * 1000000) * 1000;
}
int ret = INLINE_SYSCALL(nanosleep, 2, &sleeptime, &remainingtime);
+12 -3
View File
@@ -593,11 +593,20 @@ static int sgx_ocall_sleep(void * pms)
return 0;
}
struct timespec req, rem;
req.tv_sec = ms->ms_microsec / 1000000;
req.tv_nsec = (ms->ms_microsec - req.tv_sec * 1000000) * 1000;
unsigned long microsec = ms->ms_microsec;
#define VERY_LONG_TIME_IN_US (1000000L * 60 * 60 * 24 * 365 * 128)
if (ms->ms_microsec > VERY_LONG_TIME_IN_US) {
/* avoid overflow with time_t */
req.tv_sec = VERY_LONG_TIME_IN_US / 1000000;
req.tv_nsec = 0;
} else {
req.tv_sec = ms->ms_microsec / 1000000;
req.tv_nsec = (microsec - req.tv_sec * 1000000) * 1000;
}
ret = INLINE_SYSCALL(nanosleep, 2, &req, &rem);
if (IS_ERR(ret) && ERRNO(ret) == EINTR)
ms->ms_microsec = rem.tv_sec * 1000000 + rem.tv_nsec / 1000;
ms->ms_microsec = rem.tv_sec * 1000000UL + rem.tv_nsec / 1000UL;
return ret;
}
+9 -5
View File
@@ -139,11 +139,15 @@ int _DkThreadDelayExecution (unsigned long * duration)
struct timespec sleeptime;
struct timespec remainingtime;
long sec = (unsigned long) *duration / 1000000;
long microsec = (unsigned long) *duration - (sec * 1000000);
sleeptime.tv_sec = sec;
sleeptime.tv_nsec = microsec * 1000;
#define VERY_LONG_TIME_IN_US (1000000L * 60 * 60 * 24 * 365 * 128)
if (*duration > VERY_LONG_TIME_IN_US) {
/* avoid overflow with time_t */
sleeptime.tv_sec = VERY_LONG_TIME_IN_US / 1000000;
sleeptime.tv_nsec = 0;
} else {
sleeptime.tv_sec = *duration / 1000000;
sleeptime.tv_nsec = (*duration - sleeptime.tv_sec * 1000000) * 1000;
}
int ret = INLINE_SYSCALL(nanosleep, 2, &sleeptime, &remainingtime);