summaryrefslogtreecommitdiffstats
path: root/ipc/ipdl/test/cxx/TestInterruptShutdownRace.cpp
blob: 5482893995a8b56b012a8b8d2d8e50d125487059 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
#include "TestInterruptShutdownRace.h"

#include "base/task.h"
#include "IPDLUnitTests.h"  // fail etc.
#include "IPDLUnitTestSubprocess.h"

namespace mozilla {
namespace _ipdltest {

//-----------------------------------------------------------------------------
// parent

namespace {

// NB: this test does its own shutdown, rather than going through
// QuitParent(), because it's testing degenerate edge cases

void DeleteSubprocess() {
  gSubprocess->Destroy();
  gSubprocess = nullptr;
}

void Done() {
  passed(__FILE__);
  QuitParent();
}

}  // namespace

TestInterruptShutdownRaceParent::TestInterruptShutdownRaceParent() {
  MOZ_COUNT_CTOR(TestInterruptShutdownRaceParent);
}

TestInterruptShutdownRaceParent::~TestInterruptShutdownRaceParent() {
  MOZ_COUNT_DTOR(TestInterruptShutdownRaceParent);
}

void TestInterruptShutdownRaceParent::Main() {
  if (!SendStart()) fail("sending Start");
}

mozilla::ipc::IPCResult TestInterruptShutdownRaceParent::RecvStartDeath() {
  // this will be ordered before the OnMaybeDequeueOne event of
  // Orphan in the queue
  MessageLoop::current()->PostTask(NewNonOwningRunnableMethod(
      "_ipdltest::TestInterruptShutdownRaceParent::StartShuttingDown", this,
      &TestInterruptShutdownRaceParent::StartShuttingDown));
  return IPC_OK();
}

void TestInterruptShutdownRaceParent::StartShuttingDown() {
  // NB: we sleep here to try and avoid receiving the Orphan message
  // while waiting for the CallExit() reply.  if we fail at that, it
  // will cause the test to pass spuriously, because there won't be
  // an OnMaybeDequeueOne task for Orphan
  PR_Sleep(2000);

  if (CallExit()) fail("connection was supposed to be interrupted");

  Close();

  delete static_cast<TestInterruptShutdownRaceParent*>(gParentActor);
  gParentActor = nullptr;

  XRE_GetIOMessageLoop()->PostTask(
      NewRunnableFunction("DeleteSubprocess", DeleteSubprocess));

  // this is ordered after the OnMaybeDequeueOne event in the queue
  MessageLoop::current()->PostTask(NewRunnableFunction("Done", Done));

  // |this| has been deleted, be mindful
}

mozilla::ipc::IPCResult TestInterruptShutdownRaceParent::RecvOrphan() {
  // it would be nice to fail() here, but we'll process this message
  // while waiting for the reply CallExit().  The OnMaybeDequeueOne
  // task will still be in the queue, it just wouldn't have had any
  // work to do, if we hadn't deleted ourself
  return IPC_OK();
}

//-----------------------------------------------------------------------------
// child

TestInterruptShutdownRaceChild::TestInterruptShutdownRaceChild() {
  MOZ_COUNT_CTOR(TestInterruptShutdownRaceChild);
}

TestInterruptShutdownRaceChild::~TestInterruptShutdownRaceChild() {
  MOZ_COUNT_DTOR(TestInterruptShutdownRaceChild);
}

mozilla::ipc::IPCResult TestInterruptShutdownRaceChild::RecvStart() {
  if (!SendStartDeath()) fail("sending StartDeath");

  // See comment in StartShuttingDown(): we want to send Orphan()
  // while the parent is in its PR_Sleep()
  PR_Sleep(1000);

  if (!SendOrphan()) fail("sending Orphan");

  return IPC_OK();
}

mozilla::ipc::IPCResult TestInterruptShutdownRaceChild::AnswerExit() {
  _exit(0);
  MOZ_CRASH("unreached");
}

}  // namespace _ipdltest
}  // namespace mozilla