Pyrogenesis HEAD
Pyrogenesis, a RTS Engine
status.h File Reference
#include "lib/types.h"
#include <cstddef>
Include dependency graph for status.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Classes

struct  StatusDefinition
 
struct  StatusDefinitionBucket
 

Namespaces

namespace  INFO
 
namespace  ERR
 

Macros

#define STATUS_ADD_DEFINITIONS(definitions)   static StatusDefinitionBucket definitions##_bucket = { definitions, ARRAY_SIZE(definitions), StatusAddDefinitions(&definitions##_bucket) }
 add a module's array of StatusDefinition to the list. More...
 
#define WARN_RETURN(status)
 
#define WARN_IF_ERR(expression)
 
#define RETURN_STATUS_IF_ERR(expression)
 
#define WARN_RETURN_STATUS_IF_ERR(expression)
 
#define WARN_THROW(status)
 
#define THROW_STATUS_IF_ERR(expression)
 
#define WARN_THROW_STATUS_IF_ERR(expression)
 
#define RETURN_STATUS_FROM_CALLBACK(expression)
 
#define RETURN_0_IF_ERR(expression)
 
#define WARN_IF_FALSE(expression)
 
#define WARN_RETURN_0_IF_FALSE(expression)
 

Typedefs

typedef i64 Status
 Error handling system. More...
 

Functions

StatusDefinitionBucketStatusAddDefinitions (StatusDefinitionBucket *bucket)
 (called via STATUS_ADD_DEFINITIONS) More...
 
wchar_t * StatusDescription (Status status, wchar_t *buf, size_t max_chars)
 generate textual description of a Status. More...
 
int ErrnoFromStatus (Status status)
 
Status StatusFromErrno ()
 

Variables

const Status INFO::OK = 0
 
const Status INFO::SKIPPED = +100001
 
const Status INFO::CANNOT_HANDLE = +100002
 
const Status INFO::ALL_COMPLETE = +100003
 
const Status ERR::FAIL = -1
 
const Status ERR::LOGIC = -100010
 
const Status ERR::EXCEPTION = -100011
 
const Status ERR::TIMED_OUT = -100012
 
const Status ERR::REENTERED = -100013
 
const Status ERR::CORRUPTED = -100014
 
const Status ERR::ABORTED = -100015
 
const Status ERR::INVALID_ALIGNMENT = -100020
 
const Status ERR::INVALID_OFFSET = -100021
 
const Status ERR::INVALID_HANDLE = -100022
 
const Status ERR::INVALID_POINTER = -100023
 
const Status ERR::INVALID_SIZE = -100024
 
const Status ERR::INVALID_FLAG = -100025
 
const Status ERR::INVALID_PARAM = -100026
 
const Status ERR::INVALID_VERSION = -100027
 
const Status ERR::AGAIN = -100030
 
const Status ERR::LIMIT = -100031
 
const Status ERR::NOT_SUPPORTED = -100032
 
const Status ERR::NO_MEM = -100033
 
const Status ERR::_1 = -100101
 
const Status ERR::_2 = -100102
 
const Status ERR::_3 = -100103
 
const Status ERR::_4 = -100104
 
const Status ERR::_5 = -100105
 
const Status ERR::_6 = -100106
 
const Status ERR::_7 = -100107
 
const Status ERR::_8 = -100108
 
const Status ERR::_9 = -100109
 
const Status ERR::_11 = -100111
 
const Status ERR::_12 = -100112
 
const Status ERR::_13 = -100113
 
const Status ERR::_14 = -100114
 
const Status ERR::_15 = -100115
 
const Status ERR::_16 = -100116
 
const Status ERR::_17 = -100117
 
const Status ERR::_18 = -100118
 
const Status ERR::_19 = -100119
 
const Status ERR::_21 = -100121
 
const Status ERR::_22 = -100122
 
const Status ERR::_23 = -100123
 
const Status ERR::_24 = -100124
 
const Status ERR::_25 = -100125
 
const Status ERR::_26 = -100126
 
const Status ERR::_27 = -100127
 
const Status ERR::_28 = -100128
 
const Status ERR::_29 = -100129
 

Macro Definition Documentation

◆ RETURN_0_IF_ERR

#define RETURN_0_IF_ERR (   expression)
Value:
do\
{\
const Status status_ = (expression);\
if(status_ < 0)\
return 0;\
}\
while(0)
i64 Status
Error handling system.
Definition: status.h:173

◆ RETURN_STATUS_FROM_CALLBACK

#define RETURN_STATUS_FROM_CALLBACK (   expression)
Value:
do\
{\
const Status status_ = (expression);\
if(status_ == INFO::ALL_COMPLETE)\
return INFO::OK;\
else if(status_ != INFO::OK)\
return status_;\
}\
while(0)
const Status ALL_COMPLETE
Definition: status.h:402
const Status OK
Definition: status.h:388

◆ RETURN_STATUS_IF_ERR

#define RETURN_STATUS_IF_ERR (   expression)
Value:
do\
{\
const Status status_ = (expression);\
if(status_ < 0)\
return status_;\
}\
while(0)

◆ STATUS_ADD_DEFINITIONS

#define STATUS_ADD_DEFINITIONS (   definitions)    static StatusDefinitionBucket definitions##_bucket = { definitions, ARRAY_SIZE(definitions), StatusAddDefinitions(&definitions##_bucket) }

add a module's array of StatusDefinition to the list.

typically invoked at file scope.

Parameters
definitionsname (identifier) of the array

◆ THROW_STATUS_IF_ERR

#define THROW_STATUS_IF_ERR (   expression)
Value:
do\
{\
const Status status_ = (expression);\
if(status_ < 0)\
throw status_;\
}\
while(0)

◆ WARN_IF_ERR

#define WARN_IF_ERR (   expression)
Value:
do\
{\
const Status status_ = (expression);\
if(status_ < 0)\
DEBUG_WARN_ERR(status_);\
}\
while(0)

◆ WARN_IF_FALSE

#define WARN_IF_FALSE (   expression)
Value:
do\
{\
if(!(expression))\
debug_warn(L"FYI: WARN_IF_FALSE reports that a function failed. Feel free to ignore or suppress this warning.");\
}\
while(0)

◆ WARN_RETURN

#define WARN_RETURN (   status)
Value:
do\
{\
DEBUG_WARN_ERR(status);\
return status;\
}\
while(0)

◆ WARN_RETURN_0_IF_FALSE

#define WARN_RETURN_0_IF_FALSE (   expression)
Value:
do\
{\
if(!(expression))\
{\
debug_warn(L"FYI: WARN_RETURN_0_IF_FALSE reports that a function failed. Feel free to ignore or suppress this warning.");\
return 0;\
}\
}\
while(0)

◆ WARN_RETURN_STATUS_IF_ERR

#define WARN_RETURN_STATUS_IF_ERR (   expression)
Value:
do\
{\
const Status status_ = (expression);\
if(status_ < 0)\
{\
DEBUG_WARN_ERR(status_);\
return status_;\
}\
}\
while(0)

◆ WARN_THROW

#define WARN_THROW (   status)
Value:
do\
{\
DEBUG_WARN_ERR(status);\
throw status;\
}\
while(0)

◆ WARN_THROW_STATUS_IF_ERR

#define WARN_THROW_STATUS_IF_ERR (   expression)
Value:
do\
{\
const Status status_ = (expression);\
if(status_ < 0)\
{\
DEBUG_WARN_ERR(status_);\
throw status_;\
}\
}\
while(0)

Typedef Documentation

◆ Status

typedef i64 Status

Error handling system.

Why Error Codes?

To convey information about what failed, the alternatives are unique integral codes and direct pointers to descriptive text. Both occupy the same amount of space, but codes are easier to internationalize.

Method of Propagating Errors

When a low-level function has failed, this must be conveyed to the higher-level application logic across several functions on the call stack. There are two alternatives: 1) check at each call site whether a function failed; if so, return to the caller. 2) throw an exception.

We will discuss the advantages and disadvantages of exceptions, which are the opposites of call site checking.

  • performance: they shouldn't be used in time-critical code.
  • predictability: exceptions can come up almost anywhere, so it is hard to say what execution path will be taken.
  • interoperability: not compatible with other languages.
  • readability: cleans up code by separating application logic and error handling. however, this is also a disadvantage because it may be difficult to see at a glance if a piece of code does error checking at all.
  • visibility: errors are more likely to be seen than relying on callers to check return codes; less reliant on discipline.

Both have their place. Our recommendation is to throw error code exceptions when checking call sites and propagating errors becomes tedious. However, inter-module boundaries should always return error codes for interoperability with other languages.

Simplifying Call-Site Checking

As mentioned above, this approach requires discipline. We provide "enforcer" macros to simplify this task by propagating errors to the calling function.

Consider the following example: Status status = doWork(); if(status != INFO::OK) return status; This can be replaced by: RETURN_STATUS_IF_ERR(doWork());

This provides a visible sign that the code handles errors but reduces clutter.

When to warn the user?

When a function fails, there are 2 places we can raise a warning: as soon as the error condition is known, or higher on the call stack.

We prefer the former because it is easier to ensure that all possible return paths have been covered: search for all "return ERR::*" or "return StatusFrom*" that are not followed by a "// NOWARN" comment. The latter approach also risks multiple warnings along the call stack for the same error.

Note the special case of "validator" functions that e.g. verify the state of an object: we now discuss pros/cons of just returning errors without warning, and having their callers take care of that.

  • they typically have many return paths (-> increased code size)
  • this is balanced by validators that have many call sites.
  • we want all return statements wrapped for consistency and easily checking if any were forgotten
  • adding // NOWARN to each validator return statement would be tedious.
  • there is no advantage to checking at the call site; the call stack indicates which caller of the validator failed anyway. Validator functions should therefore also use WARN_RETURN.

Numbering Scheme

Each module header defines its own error codes to avoid a full rebuild whenever a new code is added.

Error codes start at -100000 (warnings are positive, but the corresponding negative value should not be used to avoid confusion). This scheme avoids collisions with all other known error codes.

Each header gets 100 possible values; the tens value may be used to denote groups within that header.

The subsystem is denoted by the ten-thousands digit: 0 general 1 file 2 res (resource management) 3 sysdep (system-dependent) 4 win (Windows-specific)

To summarize: +/-1SHHCC (S=subsystem, HH=header, CC=code number)

10 general 00CC misc 03CC path 04CC debug 05CC debug_stl 06CC secure_crt 07CC wchar

11 file 01CC vfs 03CC file 04CC archive

12 res 00CC h_mgr 01CC tex

13 sysdep 00CC cpu 01CC os_cpu

14 win 00CC whrt

Function Documentation

◆ ErrnoFromStatus()

int ErrnoFromStatus ( Status  status)
Returns
the errno equivalent of a Status.

used in wposix - underlying functions return Status but must be translated to errno at e.g. the mmap interface level. higher-level code that calls mmap will in turn convert back to Status.

◆ StatusAddDefinitions()

StatusDefinitionBucket * StatusAddDefinitions ( StatusDefinitionBucket bucket)

(called via STATUS_ADD_DEFINITIONS)

Parameters
bucketis being added; its definitions and numDefinitions must already be initialized.
Returns
previous bucket in list, suitable for initializing bucket->next.

(this function must be callable as a static initializer; initializing next avoids the need for a separate dummy variable)

◆ StatusDescription()

wchar_t * StatusDescription ( Status  status,
wchar_t *  buf,
size_t  max_chars 
)

generate textual description of a Status.

Parameters
bufdestination buffer (allows generating strings with the code's numerical value if no definition is found)
max_charssize of buffer [characters]
Returns
buf (allows using this function in expressions)

◆ StatusFromErrno()

Status StatusFromErrno ( )
Returns
Status equivalent of errno, or ERR::FAIL if there's no equivalent.

NB: reset errno to 0 before calling POSIX functions to avoid confusion with previous errors.