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
6632dc8d
Commit
6632dc8d
authored
Jun 04, 2013
by
Kenton Varda
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Refactor exception handling a bunch.
parent
cd02679f
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
209 additions
and
115 deletions
+209
-115
debug-test.c++
c++/src/kj/debug-test.c++
+18
-9
debug.c++
c++/src/kj/debug.c++
+29
-15
debug.h
c++/src/kj/debug.h
+25
-16
exception.c++
c++/src/kj/exception.c++
+107
-44
exception.h
c++/src/kj/exception.h
+26
-31
string.h
c++/src/kj/string.h
+4
-0
No files found.
c++/src/kj/debug-test.c++
View file @
6632dc8d
...
...
@@ -70,8 +70,9 @@ public:
throw
MockException
();
}
void
logMessage
(
StringPtr
text
)
override
{
void
logMessage
(
const
char
*
file
,
int
line
,
int
contextDepth
,
String
&&
text
)
override
{
this
->
text
+=
"log message: "
;
text
=
str
(
file
,
":"
,
line
,
":+"
,
contextDepth
,
": "
,
mv
(
text
));
this
->
text
.
append
(
text
.
begin
(),
text
.
end
());
}
};
...
...
@@ -86,11 +87,10 @@ std::string fileLine(std::string file, int line) {
TEST
(
Logging
,
Log
)
{
MockExceptionCallback
mockCallback
;
MockExceptionCallback
::
ScopedRegistration
reg
(
mockCallback
);
int
line
;
KJ_LOG
(
WARNING
,
"Hello world!"
);
line
=
__LINE__
;
EXPECT_EQ
(
"log message:
warning: "
+
fileLine
(
__FILE__
,
line
)
+
"
: Hello world!
\n
"
,
EXPECT_EQ
(
"log message:
"
+
fileLine
(
__FILE__
,
line
)
+
":+0: warning
: Hello world!
\n
"
,
mockCallback
.
text
);
mockCallback
.
text
.
clear
();
...
...
@@ -98,12 +98,12 @@ TEST(Logging, Log) {
const
char
*
str
=
"foo"
;
KJ_LOG
(
ERROR
,
i
,
str
);
line
=
__LINE__
;
EXPECT_EQ
(
"log message:
error: "
+
fileLine
(
__FILE__
,
line
)
+
"
: i = 123; str = foo
\n
"
,
EXPECT_EQ
(
"log message:
"
+
fileLine
(
__FILE__
,
line
)
+
":+0: error
: i = 123; str = foo
\n
"
,
mockCallback
.
text
);
mockCallback
.
text
.
clear
();
KJ_DBG
(
"Some debug text."
);
line
=
__LINE__
;
EXPECT_EQ
(
"log message:
debug: "
+
fileLine
(
__FILE__
,
line
)
+
"
: Some debug text.
\n
"
,
EXPECT_EQ
(
"log message:
"
+
fileLine
(
__FILE__
,
line
)
+
":+0: debug
: Some debug text.
\n
"
,
mockCallback
.
text
);
mockCallback
.
text
.
clear
();
...
...
@@ -115,7 +115,7 @@ TEST(Logging, Log) {
// Enable it.
Log
::
setLogLevel
(
Log
::
Severity
::
INFO
);
KJ_LOG
(
INFO
,
"Some text."
);
line
=
__LINE__
;
EXPECT_EQ
(
"log message:
info: "
+
fileLine
(
__FILE__
,
line
)
+
"
: Some text.
\n
"
,
EXPECT_EQ
(
"log message:
"
+
fileLine
(
__FILE__
,
line
)
+
":+0: info
: Some text.
\n
"
,
mockCallback
.
text
);
mockCallback
.
text
.
clear
();
...
...
@@ -182,7 +182,6 @@ TEST(Logging, Catch) {
TEST
(
Logging
,
Syscall
)
{
MockExceptionCallback
mockCallback
;
MockExceptionCallback
::
ScopedRegistration
reg
(
mockCallback
);
int
line
;
int
i
=
123
;
...
...
@@ -207,12 +206,17 @@ TEST(Logging, Syscall) {
TEST
(
Logging
,
Context
)
{
MockExceptionCallback
mockCallback
;
MockExceptionCallback
::
ScopedRegistration
reg
(
mockCallback
);
{
KJ_CONTEXT
(
"foo"
);
int
cline
=
__LINE__
;
EXPECT_THROW
(
KJ_FAIL_ASSERT
(
"bar"
),
MockException
);
int
line
=
__LINE__
;
KJ_LOG
(
WARNING
,
"blah"
);
int
line
=
__LINE__
;
EXPECT_EQ
(
"log message: "
+
fileLine
(
__FILE__
,
cline
)
+
":+0: context: foo
\n
"
"log message: "
+
fileLine
(
__FILE__
,
line
)
+
":+1: warning: blah
\n
"
,
mockCallback
.
text
);
mockCallback
.
text
.
clear
();
EXPECT_THROW
(
KJ_FAIL_ASSERT
(
"bar"
),
MockException
);
line
=
__LINE__
;
EXPECT_EQ
(
"fatal exception: "
+
fileLine
(
__FILE__
,
cline
)
+
": context: foo
\n
"
+
fileLine
(
__FILE__
,
line
)
+
": bug in code: bar
\n
"
,
mockCallback
.
text
);
...
...
@@ -244,6 +248,11 @@ TEST(Logging, Context) {
}
}
TEST
(
Logging
,
ExceptionCallbackMustBeOnStack
)
{
// TODO(cleanup): Put in exception-test.c++, when it exists.
EXPECT_ANY_THROW
(
new
ExceptionCallback
);
}
}
// namespace
}
// namespace internal
}
// namespace kj
c++/src/kj/debug.c++
View file @
6632dc8d
...
...
@@ -93,8 +93,8 @@ static String makeDescription(DescriptionStyle style, const char* code, int erro
++
index
;
if
(
index
!=
argValues
.
size
())
{
getExceptionCallback
().
logMessage
(
str
(
__FILE__
,
":"
,
__LINE__
,
":
Failed to parse logging macro args into "
,
getExceptionCallback
().
logMessage
(
__FILE__
,
__LINE__
,
0
,
str
(
"
Failed to parse logging macro args into "
,
argValues
.
size
(),
" names: "
,
macroArgs
,
'\n'
));
}
}
...
...
@@ -189,9 +189,8 @@ static String makeDescription(DescriptionStyle style, const char* code, int erro
void
Log
::
logInternal
(
const
char
*
file
,
int
line
,
Severity
severity
,
const
char
*
macroArgs
,
ArrayPtr
<
String
>
argValues
)
{
getExceptionCallback
().
logMessage
(
str
(
severity
,
": "
,
file
,
":"
,
line
,
": "
,
makeDescription
(
LOG
,
nullptr
,
0
,
macroArgs
,
argValues
),
'\n'
));
getExceptionCallback
().
logMessage
(
file
,
line
,
0
,
str
(
severity
,
": "
,
makeDescription
(
LOG
,
nullptr
,
0
,
macroArgs
,
argValues
),
'\n'
));
}
Log
::
Fault
::~
Fault
()
noexcept
(
false
)
{
...
...
@@ -218,9 +217,8 @@ void Log::Fault::init(
condition
,
errorNumber
,
macroArgs
,
argValues
));
}
void
Log
::
addContextToInternal
(
Exception
&
exception
,
const
char
*
file
,
int
line
,
const
char
*
macroArgs
,
ArrayPtr
<
String
>
argValues
)
{
exception
.
wrapContext
(
file
,
line
,
makeDescription
(
LOG
,
nullptr
,
0
,
macroArgs
,
argValues
));
String
Log
::
makeContextDescriptionInternal
(
const
char
*
macroArgs
,
ArrayPtr
<
String
>
argValues
)
{
return
makeDescription
(
LOG
,
nullptr
,
0
,
macroArgs
,
argValues
);
}
int
Log
::
getOsErrorNumber
()
{
...
...
@@ -228,21 +226,37 @@ int Log::getOsErrorNumber() {
return
result
==
EINTR
?
-
1
:
result
;
}
Log
::
Context
::
Context
()
:
next
(
getExceptionCallback
()),
registration
(
*
this
)
{}
Log
::
Context
::
Context
()
:
logged
(
false
)
{}
Log
::
Context
::~
Context
()
{}
Log
::
Context
::
Value
Log
::
Context
::
ensureInitialized
()
{
KJ_IF_MAYBE
(
v
,
value
)
{
return
Value
(
v
->
file
,
v
->
line
,
heapString
(
v
->
description
));
}
else
{
Value
result
=
evaluate
();
value
=
Value
(
result
.
file
,
result
.
line
,
heapString
(
result
.
description
));
return
result
;
}
}
void
Log
::
Context
::
onRecoverableException
(
Exception
&&
exception
)
{
addTo
(
exception
);
Value
v
=
ensureInitialized
();
exception
.
wrapContext
(
v
.
file
,
v
.
line
,
mv
(
v
.
description
));
next
.
onRecoverableException
(
kj
::
mv
(
exception
));
}
void
Log
::
Context
::
onFatalException
(
Exception
&&
exception
)
{
addTo
(
exception
);
Value
v
=
ensureInitialized
();
exception
.
wrapContext
(
v
.
file
,
v
.
line
,
mv
(
v
.
description
));
next
.
onFatalException
(
kj
::
mv
(
exception
));
}
void
Log
::
Context
::
logMessage
(
StringPtr
text
)
{
// TODO(someday): We could do something like log the context and then indent all log messages
// written until the end of the context.
next
.
logMessage
(
text
);
void
Log
::
Context
::
logMessage
(
const
char
*
file
,
int
line
,
int
contextDepth
,
String
&&
text
)
{
if
(
!
logged
)
{
Value
v
=
ensureInitialized
();
next
.
logMessage
(
v
.
file
,
v
.
line
,
0
,
str
(
"context: "
,
mv
(
v
.
description
),
'\n'
));
logged
=
true
;
}
next
.
logMessage
(
file
,
line
,
contextDepth
+
1
,
mv
(
text
));
}
}
// namespace kj
c++/src/kj/debug.h
View file @
6632dc8d
...
...
@@ -167,15 +167,27 @@ public:
Context
();
KJ_DISALLOW_COPY
(
Context
);
virtual
~
Context
();
virtual
void
addTo
(
Exception
&
exception
)
=
0
;
struct
Value
{
const
char
*
file
;
int
line
;
String
description
;
inline
Value
(
const
char
*
file
,
int
line
,
String
&&
description
)
:
file
(
file
),
line
(
line
),
description
(
mv
(
description
))
{}
};
virtual
Value
evaluate
()
=
0
;
virtual
void
onRecoverableException
(
Exception
&&
exception
)
override
;
virtual
void
onFatalException
(
Exception
&&
exception
)
override
;
virtual
void
logMessage
(
StringPtr
text
)
override
;
virtual
void
logMessage
(
const
char
*
file
,
int
line
,
int
contextDepth
,
String
&&
text
)
override
;
private
:
ExceptionCallback
&
next
;
ScopedRegistration
registration
;
bool
logged
;
Maybe
<
Value
>
value
;
Value
ensureInitialized
();
};
template
<
typename
Func
>
...
...
@@ -184,24 +196,22 @@ public:
inline
ContextImpl
(
Func
&
func
)
:
func
(
func
)
{}
KJ_DISALLOW_COPY
(
ContextImpl
);
void
addTo
(
Exception
&
exception
)
override
{
func
(
exception
);
Value
evaluate
(
)
override
{
return
func
(
);
}
private
:
Func
&
func
;
};
template
<
typename
...
Params
>
static
void
addContextTo
(
Exception
&
exception
,
const
char
*
file
,
int
line
,
const
char
*
macroArgs
,
Params
&&
...
params
);
static
String
makeContextDescription
(
const
char
*
macroArgs
,
Params
&&
...
params
);
private
:
static
Severity
minSeverity
;
static
void
logInternal
(
const
char
*
file
,
int
line
,
Severity
severity
,
const
char
*
macroArgs
,
ArrayPtr
<
String
>
argValues
);
static
void
addContextToInternal
(
Exception
&
exception
,
const
char
*
file
,
int
line
,
const
char
*
macroArgs
,
ArrayPtr
<
String
>
argValues
);
static
String
makeContextDescriptionInternal
(
const
char
*
macroArgs
,
ArrayPtr
<
String
>
argValues
);
static
int
getOsErrorNumber
();
// Get the error code of the last error (e.g. from errno). Returns -1 on EINTR.
...
...
@@ -243,9 +253,9 @@ ArrayPtr<const char> KJ_STRINGIFY(Log::Severity severity);
errorNumber, code, #__VA_ARGS__, ##__VA_ARGS__);; f.fatal())
#define KJ_CONTEXT(...) \
auto _kjContextFunc = [&](
::kj::Exception& exception)
{ \
return ::kj::Log::
addContextTo(exception,
\
__FILE__, __LINE__,
#__VA_ARGS__, ##__VA_ARGS__
); \
auto _kjContextFunc = [&](
) -> ::kj::Log::Context::Value
{ \
return ::kj::Log::
Context::Value(
\
__FILE__, __LINE__,
::kj::Log::makeContextDescription(#__VA_ARGS__, ##__VA_ARGS__)
); \
}; \
::kj::Log::ContextImpl<decltype(_kjContextFunc)> _kjContext(_kjContextFunc)
...
...
@@ -288,10 +298,9 @@ Log::SyscallResult Log::syscall(Call&& call) {
}
template
<
typename
...
Params
>
void
Log
::
addContextTo
(
Exception
&
exception
,
const
char
*
file
,
int
line
,
const
char
*
macroArgs
,
Params
&&
...
params
)
{
String
Log
::
makeContextDescription
(
const
char
*
macroArgs
,
Params
&&
...
params
)
{
String
argValues
[
sizeof
...(
Params
)]
=
{
str
(
params
)...};
addContextToInternal
(
exception
,
file
,
line
,
macroArgs
,
arrayPtr
(
argValues
,
sizeof
...(
Params
)));
return
makeContextDescriptionInternal
(
macroArgs
,
arrayPtr
(
argValues
,
sizeof
...(
Params
)));
}
}
// namespace kj
...
...
c++/src/kj/exception.c++
View file @
6632dc8d
...
...
@@ -146,72 +146,135 @@ namespace {
#define thread_local __thread
#endif
thread_local
ExceptionCallback
::
ScopedRegistration
*
threadLocalCallback
=
nullptr
;
ExceptionCallback
*
globalCallback
=
nullptr
;
thread_local
ExceptionCallback
*
threadLocalCallback
=
nullptr
;
class
RepeatChar
{
// A pseudo-sequence of characters that is actually just one character repeated.
//
// TODO(cleanup): Put this somewhere reusable. Maybe templatize it too.
public
:
inline
RepeatChar
(
char
c
,
uint
size
)
:
c
(
c
),
size_
(
size
)
{}
class
Iterator
{
public
:
Iterator
()
=
default
;
inline
Iterator
(
char
c
,
uint
index
)
:
c
(
c
),
index
(
index
)
{}
inline
Iterator
&
operator
++
()
{
++
index
;
return
*
this
;
}
inline
Iterator
operator
++
(
int
)
{
++
index
;
return
Iterator
(
c
,
index
-
1
);
}
inline
char
operator
*
()
const
{
return
c
;
}
inline
bool
operator
==
(
const
Iterator
&
other
)
const
{
return
index
==
other
.
index
;
}
inline
bool
operator
!=
(
const
Iterator
&
other
)
const
{
return
index
!=
other
.
index
;
}
private
:
char
c
;
uint
index
;
};
inline
uint
size
()
const
{
return
size_
;
}
inline
Iterator
begin
()
const
{
return
Iterator
(
c
,
0
);
}
inline
Iterator
end
()
const
{
return
Iterator
(
c
,
size_
);
}
private
:
char
c
;
uint
size_
;
};
inline
RepeatChar
KJ_STRINGIFY
(
RepeatChar
value
)
{
return
value
;
}
}
// namespace
ExceptionCallback
::
ExceptionCallback
()
{}
ExceptionCallback
::
ExceptionCallback
()
:
next
(
getExceptionCallback
())
{
char
stackVar
;
ptrdiff_t
offset
=
reinterpret_cast
<
char
*>
(
this
)
-
&
stackVar
;
KJ_ASSERT
(
offset
<
4096
&&
offset
>
-
4096
,
"ExceptionCallback must be allocated on the stack."
);
threadLocalCallback
=
this
;
}
ExceptionCallback
::
ExceptionCallback
(
ExceptionCallback
&
next
)
:
next
(
next
)
{}
ExceptionCallback
::~
ExceptionCallback
()
{
if
(
globalCallback
=
=
this
)
{
globalCallback
=
nullptr
;
if
(
&
next
!
=
this
)
{
threadLocalCallback
=
&
next
;
}
}
void
ExceptionCallback
::
onRecoverableException
(
Exception
&&
exception
)
{
next
.
onRecoverableException
(
mv
(
exception
));
}
void
ExceptionCallback
::
onFatalException
(
Exception
&&
exception
)
{
next
.
onFatalException
(
mv
(
exception
));
}
void
ExceptionCallback
::
logMessage
(
const
char
*
file
,
int
line
,
int
contextDepth
,
String
&&
text
)
{
next
.
logMessage
(
file
,
line
,
contextDepth
,
mv
(
text
));
}
class
ExceptionCallback
::
RootExceptionCallback
:
public
ExceptionCallback
{
public
:
RootExceptionCallback
()
:
ExceptionCallback
(
*
this
)
{}
void
onRecoverableException
(
Exception
&&
exception
)
override
{
#if KJ_NO_EXCEPTIONS
logMessage
(
str
(
exception
.
what
(),
'\n'
));
logException
(
mv
(
exception
));
#else
if
(
std
::
uncaught_exception
())
{
logMessage
(
str
(
"unwind: "
,
ExceptionImpl
(
mv
(
exception
)).
what
(),
'\n'
));
}
else
{
throw
ExceptionImpl
(
mv
(
exception
));
}
if
(
std
::
uncaught_exception
())
{
// Throwing is probably dangerous. Log instead.
logException
(
mv
(
exception
));
}
else
{
throw
ExceptionImpl
(
mv
(
exception
));
}
#endif
}
}
void
ExceptionCallback
::
onFatalException
(
Exception
&&
exception
)
{
void
onFatalException
(
Exception
&&
exception
)
override
{
#if KJ_NO_EXCEPTIONS
logMessage
(
str
(
exception
.
what
(),
'\n'
));
logException
(
mv
(
exception
));
#else
throw
ExceptionImpl
(
mv
(
exception
));
throw
ExceptionImpl
(
mv
(
exception
));
#endif
}
}
void
ExceptionCallback
::
logMessage
(
StringPtr
text
)
{
while
(
text
!=
nullptr
)
{
ssize_t
n
=
write
(
STDERR_FILENO
,
text
.
begin
(),
text
.
size
());
if
(
n
<=
0
)
{
// stderr is broken. Give up.
return
;
void
logMessage
(
const
char
*
file
,
int
line
,
int
contextDepth
,
String
&&
text
)
override
{
if
(
contextDepth
>
0
)
{
text
=
str
(
RepeatChar
(
'_'
,
contextDepth
),
mv
(
text
));
}
text
=
text
.
slice
(
n
);
}
}
void
ExceptionCallback
::
useProcessWide
()
{
KJ_REQUIRE
(
globalCallback
==
nullptr
,
"Can't register multiple global ExceptionCallbacks at once."
)
{
return
;
}
globalCallback
=
this
;
}
StringPtr
textPtr
=
text
;
ExceptionCallback
::
ScopedRegistration
::
ScopedRegistration
(
ExceptionCallback
&
callback
)
:
callback
(
callback
)
{
old
=
threadLocalCallback
;
threadLocalCallback
=
this
;
}
while
(
text
!=
nullptr
)
{
ssize_t
n
=
write
(
STDERR_FILENO
,
textPtr
.
begin
(),
textPtr
.
size
());
if
(
n
<=
0
)
{
// stderr is broken. Give up.
return
;
}
textPtr
=
textPtr
.
slice
(
n
);
}
}
ExceptionCallback
::
ScopedRegistration
::~
ScopedRegistration
()
{
threadLocalCallback
=
old
;
}
private
:
void
logException
(
Exception
&&
e
)
{
// We intentionally go back to the top exception callback on the stack because we don't want to
// bypass whatever log processing is in effect.
//
// We intentionally don't log the context since it should get re-added by the exception callback
// anyway.
getExceptionCallback
().
logMessage
(
e
.
getFile
(),
e
.
getLine
(),
0
,
str
(
e
.
getNature
(),
e
.
getDurability
()
==
Exception
::
Durability
::
TEMPORARY
?
" (temporary)"
:
""
,
e
.
getDescription
()
==
nullptr
?
""
:
": "
,
e
.
getDescription
(),
"
\n
stack: "
,
strArray
(
e
.
getStackTrace
(),
" "
)));
}
};
ExceptionCallback
&
getExceptionCallback
()
{
static
ExceptionCallback
defaultCallback
;
ExceptionCallback
::
ScopedRegistration
*
scoped
=
threadLocalCallback
;
return
scoped
!=
nullptr
?
scoped
->
getCallback
()
:
globalCallback
!=
nullptr
?
*
globalCallback
:
defaultCallback
;
static
ExceptionCallback
::
RootExceptionCallback
defaultCallback
;
ExceptionCallback
*
scoped
=
threadLocalCallback
;
return
scoped
!=
nullptr
?
*
scoped
:
defaultCallback
;
}
}
// namespace kj
c++/src/kj/exception.h
View file @
6632dc8d
...
...
@@ -125,10 +125,16 @@ String KJ_STRINGIFY(const Exception& e);
class
ExceptionCallback
{
// If you don't like C++ exceptions, you may implement and register an ExceptionCallback in order
// to perform your own exception handling.
// to perform your own exception handling. For example, a reasonable thing to do is to have
// onRecoverableException() set a flag indicating that an error occurred, and then check for that
// flag just before writing to storage and/or returning results to the user. If the flag is set,
// discard whatever you have and return an error instead.
//
// For example, a reasonable thing to do is to have onRecoverableException() set a flag
// indicating that an error occurred, and then check for that flag further up the stack.
// ExceptionCallbacks must always be allocated on the stack. When an exception is thrown, the
// newest ExceptionCallback on the calling thread's stack is called. The default implementation
// of each method calls the next-oldest ExceptionCallback for that thread. Thus the callbacks
// behave a lot like try/catch blocks, except that they are called before any stack unwinding
// occurs.
public
:
ExceptionCallback
();
...
...
@@ -138,45 +144,34 @@ public:
virtual
void
onRecoverableException
(
Exception
&&
exception
);
// Called when an exception has been raised, but the calling code has the ability to continue by
// producing garbage output. This method _should_ throw the exception, but is allowed to simply
// return if garbage output is acceptable. The default implementation throws an exception unless
// the library was compiled with -fno-exceptions, in which case it logs an error and returns.
// return if garbage output is acceptable.
//
// The global default implementation throws an exception unless the library was compiled with
// -fno-exceptions, in which case it logs an error and returns.
virtual
void
onFatalException
(
Exception
&&
exception
);
// Called when an exception has been raised and the calling code cannot continue. If this method
// returns normally, abort() will be called. The method must throw the exception to avoid
// aborting. The default implementation throws an exception unless the library was compiled with
// aborting.
//
// The global default implementation throws an exception unless the library was compiled with
// -fno-exceptions, in which case it logs an error and returns.
virtual
void
logMessage
(
StringPtr
text
);
virtual
void
logMessage
(
const
char
*
file
,
int
line
,
int
contextDepth
,
String
&&
text
);
// Called when something wants to log some debug text. The text always ends in a newline if
// it is non-empty. The default implementation writes the text to stderr.
void
useProcessWide
();
// Use this ExceptionCallback for all exceptions thrown from any thread in the process which
// doesn't otherwise have a thread-local callback. When the ExceptionCallback is destroyed,
// the default behavior will be restored. It is an error to set multiple process-wide callbacks
// at the same time.
// it is non-empty. `contextDepth` indicates how many levels of context the message passed
// through; it may make sense to indent the message accordingly.
//
// Note that to delete (and thus unregister) a global ExceptionCallback, you must ensure that
// no other threads might running code that could throw at that time. It is probably best to
// leave the callback registered permanently.
// The global default implementation writes the text to stderr.
class
ScopedRegistration
{
// Allocate a ScopedRegistration on the stack to register you ExceptionCallback just within
// the current thread. When the ScopedRegistration is destroyed, the previous thread-local
// callback will be restored.
protected
:
ExceptionCallback
&
next
;
public
:
ScopedRegistration
(
ExceptionCallback
&
callback
);
KJ_DISALLOW_COPY
(
ScopedRegistration
);
~
ScopedRegistration
();
inline
ExceptionCallback
&
getCallback
()
{
return
callback
;
}
private
:
ExceptionCallback
(
ExceptionCallback
&
next
);
private
:
ExceptionCallback
&
callback
;
ScopedRegistration
*
old
;
};
class
RootExceptionCallback
;
friend
ExceptionCallback
&
getExceptionCallback
();
};
ExceptionCallback
&
getExceptionCallback
();
...
...
c++/src/kj/string.h
View file @
6632dc8d
...
...
@@ -138,6 +138,7 @@ String heapString(size_t size);
String
heapString
(
const
char
*
value
);
String
heapString
(
const
char
*
value
,
size_t
size
);
String
heapString
(
StringPtr
value
);
String
heapString
(
const
String
&
value
);
String
heapString
(
ArrayPtr
<
const
char
>
value
);
// Allocates a copy of the given value on the heap.
...
...
@@ -374,6 +375,9 @@ inline String heapString(const char* value) {
inline
String
heapString
(
StringPtr
value
)
{
return
heapString
(
value
.
begin
(),
value
.
size
());
}
inline
String
heapString
(
const
String
&
value
)
{
return
heapString
(
value
.
begin
(),
value
.
size
());
}
inline
String
heapString
(
ArrayPtr
<
const
char
>
value
)
{
return
heapString
(
value
.
begin
(),
value
.
size
());
}
...
...
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