static void sync_with_progress(void) { unsigned long long dirty = ULONG_LONG_MAX; unsigned checks; pid_t pid; int r; BLOCK_SIGNALS(SIGCHLD); /* Due to the possiblity of the sync operation hanging, we fork a child process and monitor the progress. If * the timeout lapses, the assumption is that that particular sync stalled. */ r = asynchronous_sync(&pid); if (r < 0) { log_error_errno(r, "Failed to fork sync(): %m"); return; } log_info("Syncing filesystems and block devices."); /* Start monitoring the sync operation. If more than * SYNC_PROGRESS_ATTEMPTS lapse without progress being made, * we assume that the sync is stalled */ for (checks = 0; checks < SYNC_PROGRESS_ATTEMPTS; checks++) { r = wait_for_terminate_with_timeout(pid, SYNC_TIMEOUT_USEC); if (r == 0) /* Sync finished without error. * (The sync itself does not return an error code) */ return; else if (r == -ETIMEDOUT) { /* Reset the check counter if the "Dirty" value is * decreasing */ if (sync_making_progress(&dirty)) checks = 0; } else { log_error_errno(r, "Failed to sync filesystems and block devices: %m"); return; } } /* Only reached in the event of a timeout. We should issue a kill * to the stray process. */ log_error("Syncing filesystems and block devices - timed out, issuing SIGKILL to PID "PID_FMT".", pid); (void) kill(pid, SIGKILL); }
int main(int argc, char *argv[]) { int fd; char name[] = "/tmp/test-asynchronous_close.XXXXXX"; fd = mkostemp_safe(name); assert_se(fd >= 0); asynchronous_close(fd); assert_se(asynchronous_job(async_func, NULL) >= 0); assert_se(asynchronous_sync(NULL) >= 0); sleep(1); assert_se(fcntl(fd, F_GETFD) == -1); assert_se(test_async); unlink(name); return 0; }