test: separate quick, live, and stress checks
This commit is contained in:
@@ -11,7 +11,6 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/inotify.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
@@ -28,10 +27,6 @@ enum
|
||||
Starttimeout = 8000,
|
||||
Stoptimeout = 3000,
|
||||
Ctrlmask = 1<<2,
|
||||
|
||||
Phaseignore,
|
||||
Phasequiet,
|
||||
Phaserecover,
|
||||
};
|
||||
|
||||
typedef struct Test Test;
|
||||
@@ -45,19 +40,9 @@ struct Test
|
||||
int firsterrfd;
|
||||
int seconderrfd;
|
||||
int helpererrfd;
|
||||
int notifyfd;
|
||||
int runtimewd;
|
||||
int buswd;
|
||||
int ipcfirst;
|
||||
int ipcnew;
|
||||
int busfirstfd;
|
||||
int phase;
|
||||
int socketdeleted;
|
||||
int socketcreated;
|
||||
int bustempcreated;
|
||||
int bustempmoved;
|
||||
int buspublished;
|
||||
uint32_t buscookie;
|
||||
DBusConnection *busfirst;
|
||||
DBusConnection *busnew;
|
||||
char root[256];
|
||||
@@ -68,18 +53,8 @@ struct Test
|
||||
char home[320];
|
||||
char socket[384];
|
||||
char addrfile[512];
|
||||
char addrbase[256];
|
||||
char firstaddress[512];
|
||||
char secondaddress[512];
|
||||
char firstcontents[2048];
|
||||
size_t nfirstcontents;
|
||||
char secondcontents[2048];
|
||||
size_t nsecondcontents;
|
||||
char bustemp[256];
|
||||
struct stat firstsocketst;
|
||||
struct stat firstaddrst;
|
||||
struct stat secondsocketst;
|
||||
struct stat secondaddrst;
|
||||
char firsterr[8192];
|
||||
size_t nfirsterr;
|
||||
char seconderr[8192];
|
||||
@@ -88,9 +63,6 @@ struct Test
|
||||
size_t nhelpererr;
|
||||
};
|
||||
|
||||
static uint32_t watchmask = IN_CREATE|IN_DELETE|IN_ATTRIB|IN_MOVED_FROM|
|
||||
IN_MOVED_TO|IN_CLOSE_WRITE|IN_DELETE_SELF|IN_MOVE_SELF;
|
||||
|
||||
static int
|
||||
fail(char *fmt, ...)
|
||||
{
|
||||
@@ -191,13 +163,9 @@ setup(Test *t)
|
||||
t->firsterrfd = -1;
|
||||
t->seconderrfd = -1;
|
||||
t->helpererrfd = -1;
|
||||
t->notifyfd = -1;
|
||||
t->runtimewd = -1;
|
||||
t->buswd = -1;
|
||||
t->ipcfirst = -1;
|
||||
t->ipcnew = -1;
|
||||
t->busfirstfd = -1;
|
||||
t->phase = Phaseignore;
|
||||
memset(&sa, 0, sizeof sa);
|
||||
sa.sa_handler = SIG_DFL;
|
||||
if(sigemptyset(&sa.sa_mask) < 0 || sigaction(SIGCHLD, &sa, NULL) < 0)
|
||||
@@ -225,15 +193,6 @@ setup(Test *t)
|
||||
if(!makedir(t->runtime) || !makedir(t->config) || !makedir(t->ibus) ||
|
||||
!makedir(t->bus) || !makedir(t->home))
|
||||
return 0;
|
||||
t->notifyfd = inotify_init1(IN_CLOEXEC|IN_NONBLOCK);
|
||||
if(t->notifyfd < 0)
|
||||
return fail("inotify_init1: %s", strerror(errno));
|
||||
t->runtimewd = inotify_add_watch(t->notifyfd, t->runtime, watchmask);
|
||||
if(t->runtimewd < 0)
|
||||
return fail("watch runtime directory: %s", strerror(errno));
|
||||
t->buswd = inotify_add_watch(t->notifyfd, t->bus, watchmask);
|
||||
if(t->buswd < 0)
|
||||
return fail("watch IBus directory: %s", strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -284,7 +243,8 @@ startchild(Test *t, char *program, char *mapdir, pid_t *child, int *errfd)
|
||||
setenv("XDG_CONFIG_HOME", t->config, 1) < 0 ||
|
||||
setenv("HOME", t->home, 1) < 0 || unsetenv("DISPLAY") < 0 ||
|
||||
unsetenv("DBUS_SESSION_BUS_ADDRESS") < 0 ||
|
||||
unsetenv("IBUS_ADDRESS") < 0){
|
||||
unsetenv("IBUS_ADDRESS") < 0 ||
|
||||
unsetenv("IBUS_ADDRESS_FILE") < 0){
|
||||
dprintf(STDERR_FILENO, "set daemon environment: %s\n",
|
||||
strerror(errno));
|
||||
_exit(126);
|
||||
@@ -299,150 +259,6 @@ startchild(Test *t, char *program, char *mapdir, pid_t *child, int *errfd)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
runtimeevent(Test *t, struct inotify_event *ev)
|
||||
{
|
||||
uint32_t mask;
|
||||
|
||||
if(ev->len == 0 || strcmp(ev->name, "strans.sock") != 0)
|
||||
return fail("unexpected runtime entry event %#x for %s", ev->mask,
|
||||
ev->len != 0 ? ev->name : "directory");
|
||||
mask = ev->mask & watchmask;
|
||||
if(mask & IN_DELETE){
|
||||
if(t->socketdeleted || t->socketcreated)
|
||||
return fail("IPC socket deletion occurred out of order");
|
||||
t->socketdeleted = 1;
|
||||
mask &= ~IN_DELETE;
|
||||
}
|
||||
if(mask & IN_CREATE){
|
||||
if(!t->socketdeleted || t->socketcreated)
|
||||
return fail("IPC socket creation occurred before stale deletion");
|
||||
t->socketcreated = 1;
|
||||
mask &= ~IN_CREATE;
|
||||
}
|
||||
if(mask & IN_ATTRIB){
|
||||
if(!t->socketcreated)
|
||||
return fail("IPC socket protection occurred before recreation");
|
||||
mask &= ~IN_ATTRIB;
|
||||
}
|
||||
if(mask != 0)
|
||||
return fail("unexpected IPC recovery event %#x", ev->mask);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
tempname(Test *t, char *name)
|
||||
{
|
||||
size_t n, nn;
|
||||
|
||||
n = strlen(t->addrbase);
|
||||
nn = strlen(name);
|
||||
if(nn <= n + 5)
|
||||
return 0;
|
||||
return strncmp(name, t->addrbase, n) == 0 &&
|
||||
strncmp(name + n, ".tmp.", 5) == 0;
|
||||
}
|
||||
|
||||
static int
|
||||
busevent(Test *t, struct inotify_event *ev)
|
||||
{
|
||||
uint32_t mask;
|
||||
|
||||
if(ev->len == 0)
|
||||
return fail("unexpected unnamed IBus directory event %#x", ev->mask);
|
||||
mask = ev->mask & watchmask;
|
||||
if(tempname(t, ev->name)){
|
||||
if(mask & IN_CREATE){
|
||||
if(t->bustempcreated || snprintf(t->bustemp, sizeof t->bustemp,
|
||||
"%s", ev->name) >= (int)sizeof t->bustemp)
|
||||
return fail("invalid replacement IBus temporary file");
|
||||
t->bustempcreated = 1;
|
||||
mask &= ~IN_CREATE;
|
||||
}
|
||||
if(!t->bustempcreated || strcmp(ev->name, t->bustemp) != 0)
|
||||
return fail("unowned IBus temporary file event for %s", ev->name);
|
||||
if(mask & IN_ATTRIB)
|
||||
mask &= ~IN_ATTRIB;
|
||||
if(mask & IN_CLOSE_WRITE)
|
||||
mask &= ~IN_CLOSE_WRITE;
|
||||
if(mask & IN_MOVED_FROM){
|
||||
if(t->bustempmoved || ev->cookie == 0)
|
||||
return fail("invalid IBus temporary-file rename");
|
||||
t->bustempmoved = 1;
|
||||
t->buscookie = ev->cookie;
|
||||
mask &= ~IN_MOVED_FROM;
|
||||
}
|
||||
if(mask != 0)
|
||||
return fail("unexpected IBus temporary-file event %#x", ev->mask);
|
||||
return 1;
|
||||
}
|
||||
if(strcmp(ev->name, t->addrbase) != 0)
|
||||
return fail("unexpected IBus recovery entry %s", ev->name);
|
||||
if(mask == IN_MOVED_TO && t->bustempmoved && ev->cookie == t->buscookie){
|
||||
t->buspublished = 1;
|
||||
return 1;
|
||||
}
|
||||
return fail("IBus address replacement was not one atomic rename: %#x",
|
||||
ev->mask);
|
||||
}
|
||||
|
||||
static int
|
||||
drainnotify(Test *t)
|
||||
{
|
||||
char buf[4096];
|
||||
struct inotify_event *ev;
|
||||
ssize_t n;
|
||||
size_t off;
|
||||
int ok;
|
||||
|
||||
ok = 1;
|
||||
for(;;){
|
||||
n = read(t->notifyfd, buf, sizeof buf);
|
||||
if(n < 0 && errno == EINTR)
|
||||
continue;
|
||||
if(n < 0 && errno == EAGAIN)
|
||||
return ok;
|
||||
if(n < 0)
|
||||
return fail("read endpoint watches: %s", strerror(errno));
|
||||
if(n == 0)
|
||||
return ok;
|
||||
for(off = 0; off + sizeof *ev <= (size_t)n;
|
||||
off += sizeof *ev + ev->len){
|
||||
ev = (struct inotify_event*)(buf + off);
|
||||
if(off + sizeof *ev + ev->len > (size_t)n)
|
||||
return fail("truncated inotify event");
|
||||
if(ev->mask & IN_Q_OVERFLOW){
|
||||
fail("endpoint watch queue overflowed");
|
||||
ok = 0;
|
||||
continue;
|
||||
}
|
||||
if(ev->mask & (IN_IGNORED|IN_UNMOUNT)){
|
||||
fail("endpoint watch became invalid: %#x", ev->mask);
|
||||
ok = 0;
|
||||
continue;
|
||||
}
|
||||
if(ev->wd != t->runtimewd && ev->wd != t->buswd)
|
||||
continue;
|
||||
if(t->phase == Phaseignore)
|
||||
continue;
|
||||
if(t->phase == Phasequiet){
|
||||
fail("hard crash changed %s endpoint %s with event %#x",
|
||||
ev->wd == t->runtimewd ? "IPC" : "IBus",
|
||||
ev->len != 0 ? ev->name : "directory", ev->mask);
|
||||
ok = 0;
|
||||
continue;
|
||||
}
|
||||
if(ev->wd == t->runtimewd){
|
||||
if(!runtimeevent(t, ev))
|
||||
ok = 0;
|
||||
}else if(!busevent(t, ev))
|
||||
ok = 0;
|
||||
}
|
||||
if(off != (size_t)n)
|
||||
return fail("truncated inotify event buffer");
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
findaddress(Test *t)
|
||||
{
|
||||
@@ -600,9 +416,9 @@ childalive(pid_t *pid, char *which)
|
||||
static int
|
||||
waitready(Test *t, pid_t *child, int errfd, char *which)
|
||||
{
|
||||
struct pollfd pfd[2];
|
||||
struct pollfd pfd;
|
||||
struct stat st;
|
||||
char contents[2048], address[512];
|
||||
char contents[2048], *address;
|
||||
size_t ncontents;
|
||||
pid_t declared;
|
||||
int count, n, socketready, timeout;
|
||||
@@ -613,6 +429,7 @@ waitready(Test *t, pid_t *child, int errfd, char *which)
|
||||
return fail("read monotonic clock before %s startup: %s", which,
|
||||
strerror(errno));
|
||||
deadline += Starttimeout;
|
||||
address = child == &t->first ? t->firstaddress : t->secondaddress;
|
||||
for(;;){
|
||||
socketready = lstat(t->socket, &st) == 0 && S_ISSOCK(st.st_mode) &&
|
||||
(st.st_mode & 0777) == 0600;
|
||||
@@ -621,7 +438,7 @@ waitready(Test *t, pid_t *child, int errfd, char *which)
|
||||
return 0;
|
||||
if(socketready && count == 1 &&
|
||||
readfile(t->addrfile, contents, sizeof contents, &ncontents) &&
|
||||
parseaddress(contents, ncontents, address, sizeof address,
|
||||
parseaddress(contents, ncontents, address, 512,
|
||||
&declared) && declared == *child && privateaddress(address, declared))
|
||||
return 1;
|
||||
if(!childalive(child, which))
|
||||
@@ -632,27 +449,19 @@ waitready(Test *t, pid_t *child, int errfd, char *which)
|
||||
strerror(errno));
|
||||
if(timeout == 0)
|
||||
return fail("timed out waiting for both %s daemon endpoints", which);
|
||||
pfd[0].fd = t->notifyfd;
|
||||
pfd[0].events = POLLIN;
|
||||
pfd[0].revents = 0;
|
||||
pfd[1].fd = errfd;
|
||||
pfd[1].events = POLLIN|POLLHUP;
|
||||
pfd[1].revents = 0;
|
||||
n = poll(pfd, 2, timeout);
|
||||
pfd.fd = errfd;
|
||||
pfd.events = POLLIN|POLLHUP;
|
||||
pfd.revents = 0;
|
||||
n = poll(&pfd, 1, timeout > 20 ? 20 : timeout);
|
||||
if(n < 0 && errno == EINTR)
|
||||
continue;
|
||||
if(n < 0)
|
||||
return fail("poll %s daemon readiness: %s", which,
|
||||
strerror(errno));
|
||||
if(pfd[0].revents & (POLLERR|POLLHUP|POLLNVAL))
|
||||
return fail("endpoint watch became unusable: %#x", pfd[0].revents);
|
||||
if(pfd[1].revents & (POLLERR|POLLNVAL))
|
||||
if(pfd.revents & (POLLERR|POLLNVAL))
|
||||
return fail("%s stderr pipe became unusable: %#x", which,
|
||||
pfd[1].revents);
|
||||
if(pfd[0].revents & POLLIN)
|
||||
if(!drainnotify(t))
|
||||
return 0;
|
||||
if(pfd[1].revents & (POLLIN|POLLHUP)){
|
||||
pfd.revents);
|
||||
if(pfd.revents & (POLLIN|POLLHUP)){
|
||||
if(child == &t->first)
|
||||
readpipe(errfd, t->firsterr, sizeof t->firsterr,
|
||||
&t->nfirsterr);
|
||||
@@ -663,39 +472,6 @@ waitready(Test *t, pid_t *child, int errfd, char *which)
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
snapshotfirst(Test *t)
|
||||
{
|
||||
char *base;
|
||||
pid_t declared;
|
||||
|
||||
if(lstat(t->socket, &t->firstsocketst) < 0)
|
||||
return fail("stat first IPC socket: %s", strerror(errno));
|
||||
if(!S_ISSOCK(t->firstsocketst.st_mode) ||
|
||||
(t->firstsocketst.st_mode & 0777) != 0600)
|
||||
return fail("first IPC endpoint is not a protected socket");
|
||||
if(lstat(t->addrfile, &t->firstaddrst) < 0)
|
||||
return fail("stat first IBus address file: %s", strerror(errno));
|
||||
if(!S_ISREG(t->firstaddrst.st_mode) ||
|
||||
(t->firstaddrst.st_mode & 0777) != 0600)
|
||||
return fail("first IBus address is not a protected regular file");
|
||||
if(!readfile(t->addrfile, t->firstcontents, sizeof t->firstcontents,
|
||||
&t->nfirstcontents) ||
|
||||
!parseaddress(t->firstcontents, t->nfirstcontents, t->firstaddress,
|
||||
sizeof t->firstaddress, &declared))
|
||||
return 0;
|
||||
if(declared != t->firstpid)
|
||||
return fail("first IBus address PID %ld, expected %ld", (long)declared,
|
||||
(long)t->firstpid);
|
||||
if(!privateaddress(t->firstaddress, declared))
|
||||
return 0;
|
||||
base = strrchr(t->addrfile, '/');
|
||||
if(base == NULL || snprintf(t->addrbase, sizeof t->addrbase, "%s", base+1)
|
||||
>= (int)sizeof t->addrbase)
|
||||
return fail("first IBus address filename is invalid");
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
connectsocket(char *path, int64_t deadline)
|
||||
{
|
||||
@@ -1200,47 +976,6 @@ waitbusclosed(Test *t)
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
onlyaddress(Test *t, char *where)
|
||||
{
|
||||
DIR *dir;
|
||||
struct dirent *de;
|
||||
int count, ok;
|
||||
|
||||
dir = opendir(t->bus);
|
||||
if(dir == NULL)
|
||||
return fail("open IBus directory %s %s: %s", t->bus, where,
|
||||
strerror(errno));
|
||||
count = 0;
|
||||
ok = 1;
|
||||
errno = 0;
|
||||
while((de = readdir(dir)) != NULL){
|
||||
if(strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
|
||||
continue;
|
||||
count++;
|
||||
if(strcmp(de->d_name, t->addrbase) != 0){
|
||||
fail("unexpected IBus entry %s %s", de->d_name, where);
|
||||
ok = 0;
|
||||
}
|
||||
errno = 0;
|
||||
}
|
||||
if(errno != 0){
|
||||
fail("read IBus directory %s %s: %s", t->bus, where,
|
||||
strerror(errno));
|
||||
ok = 0;
|
||||
}
|
||||
if(closedir(dir) < 0){
|
||||
fail("close IBus directory %s %s: %s", t->bus, where,
|
||||
strerror(errno));
|
||||
ok = 0;
|
||||
}
|
||||
if(count != 1){
|
||||
fail("IBus directory has %d entries %s", count, where);
|
||||
ok = 0;
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
static int
|
||||
checkstale(Test *t)
|
||||
{
|
||||
@@ -1251,24 +986,16 @@ checkstale(Test *t)
|
||||
|
||||
if(lstat(t->socket, &st) < 0)
|
||||
return fail("stale IPC socket disappeared: %s", strerror(errno));
|
||||
if(!S_ISSOCK(st.st_mode) || st.st_mode != t->firstsocketst.st_mode ||
|
||||
st.st_dev != t->firstsocketst.st_dev ||
|
||||
st.st_ino != t->firstsocketst.st_ino)
|
||||
return fail("stale IPC socket identity or protection changed");
|
||||
if(!S_ISSOCK(st.st_mode))
|
||||
return fail("stale IPC endpoint is not a socket");
|
||||
if(lstat(t->addrfile, &st) < 0)
|
||||
return fail("stale IBus address file disappeared: %s", strerror(errno));
|
||||
if(st.st_mode != t->firstaddrst.st_mode ||
|
||||
st.st_dev != t->firstaddrst.st_dev || st.st_ino != t->firstaddrst.st_ino)
|
||||
return fail("stale IBus address identity or protection changed");
|
||||
if(!readfile(t->addrfile, contents, sizeof contents, &ncontents) ||
|
||||
!parseaddress(contents, ncontents, address, sizeof address, &declared))
|
||||
return 0;
|
||||
if(ncontents != t->nfirstcontents ||
|
||||
memcmp(contents, t->firstcontents, ncontents) != 0)
|
||||
return fail("stale IBus address contents changed after hard crash");
|
||||
if(declared != t->firstpid || strcmp(address, t->firstaddress) != 0)
|
||||
return fail("stale IBus address no longer names the dead first daemon");
|
||||
return onlyaddress(t, "after hard crash");
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -1479,52 +1206,6 @@ rejectold(Test *t, char *self, char *where)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
recoveryevents(Test *t)
|
||||
{
|
||||
if(!t->socketdeleted || !t->socketcreated)
|
||||
return fail("replacement did not delete and recreate the stale IPC path");
|
||||
if(!t->bustempcreated || !t->bustempmoved || !t->buspublished)
|
||||
return fail("replacement IBus address was not atomically published");
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
snapshotsecond(Test *t)
|
||||
{
|
||||
pid_t declared;
|
||||
|
||||
if(lstat(t->socket, &t->secondsocketst) < 0)
|
||||
return fail("stat replacement IPC socket: %s", strerror(errno));
|
||||
if(!S_ISSOCK(t->secondsocketst.st_mode) ||
|
||||
(t->secondsocketst.st_mode & 0777) != 0600)
|
||||
return fail("replacement IPC endpoint is not a protected socket");
|
||||
if(lstat(t->addrfile, &t->secondaddrst) < 0)
|
||||
return fail("stat replacement IBus address file: %s", strerror(errno));
|
||||
if(!S_ISREG(t->secondaddrst.st_mode) ||
|
||||
(t->secondaddrst.st_mode & 0777) != 0600)
|
||||
return fail("replacement IBus address is not a protected regular file");
|
||||
if(t->secondaddrst.st_dev == t->firstaddrst.st_dev &&
|
||||
t->secondaddrst.st_ino == t->firstaddrst.st_ino)
|
||||
return fail("replacement IBus address retained the stale inode");
|
||||
if(!readfile(t->addrfile, t->secondcontents, sizeof t->secondcontents,
|
||||
&t->nsecondcontents) ||
|
||||
!parseaddress(t->secondcontents, t->nsecondcontents, t->secondaddress,
|
||||
sizeof t->secondaddress, &declared))
|
||||
return 0;
|
||||
if(declared != t->second)
|
||||
return fail("replacement IBus address PID %ld, expected %ld",
|
||||
(long)declared, (long)t->second);
|
||||
if(!privateaddress(t->secondaddress, declared))
|
||||
return 0;
|
||||
if(t->nsecondcontents == t->nfirstcontents &&
|
||||
memcmp(t->secondcontents, t->firstcontents, t->nfirstcontents) == 0)
|
||||
return fail("replacement IBus address contents did not change");
|
||||
if(strcmp(t->secondaddress, t->firstaddress) == 0)
|
||||
return fail("replacement reused the dead private IBus address");
|
||||
return onlyaddress(t, "after replacement");
|
||||
}
|
||||
|
||||
static int
|
||||
openreplacement(Test *t)
|
||||
{
|
||||
@@ -1747,7 +1428,6 @@ cleanup(Test *t)
|
||||
ok = 0;
|
||||
if(t->first > 0 && !killreap(&t->first, t->firsterrfd, "first daemon"))
|
||||
ok = 0;
|
||||
t->phase = Phaseignore;
|
||||
if(!stopsecond(t))
|
||||
ok = 0;
|
||||
readpipe(t->firsterrfd, t->firsterr, sizeof t->firsterr, &t->nfirsterr);
|
||||
@@ -1776,23 +1456,6 @@ cleanup(Test *t)
|
||||
}
|
||||
t->helpererrfd = -1;
|
||||
}
|
||||
if(t->notifyfd >= 0){
|
||||
if(t->runtimewd >= 0 &&
|
||||
inotify_rm_watch(t->notifyfd, t->runtimewd) < 0 && errno != EINVAL){
|
||||
fail("remove runtime watch: %s", strerror(errno));
|
||||
ok = 0;
|
||||
}
|
||||
if(t->buswd >= 0 &&
|
||||
inotify_rm_watch(t->notifyfd, t->buswd) < 0 && errno != EINVAL){
|
||||
fail("remove IBus watch: %s", strerror(errno));
|
||||
ok = 0;
|
||||
}
|
||||
if(close(t->notifyfd) < 0){
|
||||
fail("close endpoint watches: %s", strerror(errno));
|
||||
ok = 0;
|
||||
}
|
||||
t->notifyfd = -1;
|
||||
}
|
||||
if(!removeroot(t))
|
||||
ok = 0;
|
||||
return ok;
|
||||
@@ -1805,23 +1468,19 @@ runrestart(Test *t, char *self, char *program, char *mapdir)
|
||||
return 0;
|
||||
t->firstpid = t->first;
|
||||
if(!waitready(t, &t->first, t->firsterrfd, "first") ||
|
||||
!snapshotfirst(t) || !openpersistent(t) || !drainnotify(t))
|
||||
!openpersistent(t))
|
||||
return 0;
|
||||
t->phase = Phasequiet;
|
||||
if(!hardcrash(t) || !waitipcclosed(t) || !waitbusclosed(t) ||
|
||||
!drainnotify(t) || !checkstale(t) ||
|
||||
!rejectold(t, self, "after hard crash") || !drainnotify(t))
|
||||
!checkstale(t) || !rejectold(t, self, "after hard crash"))
|
||||
return 0;
|
||||
closebus(&t->busfirst);
|
||||
if(close(t->ipcfirst) < 0)
|
||||
return fail("close disconnected persistent IPC client: %s",
|
||||
strerror(errno));
|
||||
t->ipcfirst = -1;
|
||||
t->phase = Phaserecover;
|
||||
if(!startchild(t, program, mapdir, &t->second, &t->seconderrfd) ||
|
||||
!waitready(t, &t->second, t->seconderrfd, "second") ||
|
||||
!drainnotify(t) || !recoveryevents(t) || !snapshotsecond(t) ||
|
||||
!rejectold(t, self, "after replacement") || !openreplacement(t))
|
||||
!openreplacement(t))
|
||||
return 0;
|
||||
return childalive(&t->second, "second");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user