Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
C
capnproto
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
capnproto
Commits
d67392cf
Commit
d67392cf
authored
Aug 02, 2013
by
Kenton Varda
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Apparently at_quick_exit() doesn't exist on most platforms. Oh well, just use _Exit().
parent
56659da1
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
61 additions
and
2 deletions
+61
-2
main.c++
c++/src/kj/main.c++
+1
-1
main.h
c++/src/kj/main.h
+60
-1
No files found.
c++/src/kj/main.c++
View file @
d67392cf
...
@@ -56,7 +56,7 @@ void TopLevelProcessContext::exit() {
...
@@ -56,7 +56,7 @@ void TopLevelProcessContext::exit() {
throw
CleanShutdownException
{
exitCode
};
throw
CleanShutdownException
{
exitCode
};
#endif
#endif
}
}
quick_e
xit
(
exitCode
);
_E
xit
(
exitCode
);
}
}
static
void
writeLineToFd
(
int
fd
,
StringPtr
message
)
{
static
void
writeLineToFd
(
int
fd
,
StringPtr
message
)
{
...
...
c++/src/kj/main.h
View file @
d67392cf
...
@@ -40,10 +40,69 @@ public:
...
@@ -40,10 +40,69 @@ public:
virtual
void
exit
()
KJ_NORETURN
=
0
;
virtual
void
exit
()
KJ_NORETURN
=
0
;
// Indicates program completion. The program is considered successful unless `error()` was
// Indicates program completion. The program is considered successful unless `error()` was
// called. Typically this exits with
quick_e
xit(), meaning that the stack is not unwound, buffers
// called. Typically this exits with
_E
xit(), meaning that the stack is not unwound, buffers
// are not flushed, etc. -- it is the responsibility of the caller to flush any buffers that
// are not flushed, etc. -- it is the responsibility of the caller to flush any buffers that
// matter. However, an alternate context implementation e.g. for unit testing purposes could
// matter. However, an alternate context implementation e.g. for unit testing purposes could
// choose to throw an exception instead.
// choose to throw an exception instead.
//
// At first this approach may sound crazy. Isn't it much better to shut down cleanly? What if
// you lose data? However, it turns out that if you look at each common class of program, _Exit()
// is almost always preferable. Let's break it down:
//
// * Commands: A typical program you might run from the command line is single-threaded and
// exits quickly and deterministically. Commands often use buffered I/O and need to flush
// those buffers before exit. However, most of the work performed by destructors is not
// flushing buffers, but rather freeing up memory, placing objects into freelists, and closing
// file descriptors. All of this is irrelevant if the process is about to exit anyway, and
// for a command that runs quickly, time wasted freeing heap space may make a real difference
// in the overall runtime of a script. Meanwhile, it is usually easy to determine exactly what
// resources need to be flushed before exit, and easy to tell if they are not being flushed
// (because the command fails to produce the expected output). Therefore, it is reasonably
// easy for commands to explicitly ensure all output is flushed before exiting, and it is
// probably a good idea for them to do so anyway, because write failures should be detected
// and handled. For commands, a good strategy is to allocate any objects that require clean
// destruction on the stack, and allow them to go out of scope before the command exits.
// Meanwhile, any resources which do not need to be cleaned up should be allocated as members
// of the command's main class, whose destructor normally will not be called.
//
// * Interactive apps: Programs that interact with the user (whether they be graphical apps
// with windows or console-based apps like emacs) generally exit only when the user asks them
// to. Such applications may store large data structures in memory which need to be synced
// to disk, such as documents or user preferences. However, relying on stack unwind or global
// destructors as the mechanism for ensuring such syncing occurs is probably wrong. First of
// all, it's 2013, and applications ought to be actively syncing changes to non-volatile
// storage the moment those changes are made. Applications can crash at any time and a crash
// should never lose data that is more than half a second old. Meanwhile, if a user actually
// does try to close an application while unsaved changes exist, the application UI should
// prompt the user to decide what to do. Such a UI mechanism is obviously too high level to
// be implemented via destructors, so KJ's use of _Exit() shouldn't make a difference here.
//
// * Servers: A good server is fault-tolerant, prepared for the possibility that at any time
// it could crash, the OS could decide to kill it off, or the machine it is running on could
// just die. So, using _Exit() should be no problem. In fact, servers generally never even
// call exit anyway; they are killed externally.
//
// * Batch jobs: A long-running batch job is something between a command and a server. It
// probably knows exactly what needs to be flushed before exiting, and it probably should be
// fault-tolerant.
//
// Meanwhile, regardless of program type, if you are adhering to KJ style, then the use of
// _Exit() shouldn't be a problem anyway:
//
// * KJ style forbids global mutable state (singletons) in general and global constructors and
// destructors in particular. Therefore, everything that could possibly need cleanup either
// lives on the stack or is transitively owned by something living on the stack.
//
// * Calling exit() simply means "Don't clean up anything older than this stack frame.". If you
// have resources that require cleanup before exit, make sure they are owned by stack frames
// beyond the one that eventually calls exit(). To be as safe as possible, don't place any
// state in your program's main class, and don't call exit() yourself. Then, runMainAndExit()
// will do it, and the only thing on the stack at that time will be your main class, which
// has no state anyway.
//
// TODO(someday): Perhaps we should use the new std::quick_exit(), so that at_quick_exit() is
// available for those who really think they need it. Unfortunately, it is not yet available
// on many platforms.
virtual
void
warning
(
StringPtr
message
)
=
0
;
virtual
void
warning
(
StringPtr
message
)
=
0
;
// Print the given message to standard error. A newline is printed after the message if it
// Print the given message to standard error. A newline is printed after the message if it
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment