From 676fe95ef37955a7135162716132d0de6ed71350 Mon Sep 17 00:00:00 2001 From: Vitalii Koshura Date: Tue, 21 Feb 2023 01:13:12 +0100 Subject: [PATCH] Update BasicApi.md file Signed-off-by: Vitalii Koshura --- BasicApi.md | 256 +++++++++++++++++++++++++--------------------------- 1 file changed, 122 insertions(+), 134 deletions(-) diff --git a/BasicApi.md b/BasicApi.md index 70ad582..11c9901 100644 --- a/BasicApi.md +++ b/BasicApi.md @@ -1,120 +1,116 @@ -[[PageOutline]] +# The BOINC application programming interface (API) + The BOINC API is a set of C++ functions. Most of the functions have a C interface, so that they can be used from programs written in C and other languages. Unless otherwise specified, the functions return an integer error code; zero indicates success. To use the API include the header file: - - #include "boinc_api.h" - +``` +#include "boinc_api.h" +``` BOINC applications may have an associate graphics program, which can act as a screensaver. The API for these graphics apps is [here](GraphicsApps). -# Initialization #init +# Initialization Initialization must be done before calling other BOINC functions. For sequential (single-threaded) apps, call - - boinc_init(); - +``` +boinc_init(); +``` -## Parallel apps +# Parallel apps If your uses multiple threads or processes for parallelism, initialize using - - BOINC_OPTIONS options; - - boinc_options_defaults(options); - options.multi_thread = true; // if your app's main process uses multiple threads - options.multi_process = true; // if your app uses multiple processes - - boinc_init_options(&options); - +``` +BOINC_OPTIONS options; + +boinc_options_defaults(options); +options.multi_thread = true; // if your app's main process uses multiple threads +options.multi_process = true; // if your app uses multiple processes + +boinc_init_options(&options); +``` Do this before creating any threads or processes, or storing the PID. -## GPU and coprocessor apps +# GPU and coprocessor apps If your app uses GPUs or coprocessors, initialize using - - BOINC_OPTIONS options; - - boinc_options_defaults(options); - options.normal_thread_priority = true; - boinc_init_options(&options); - +``` +BOINC_OPTIONS options; + +boinc_options_defaults(options); +options.normal_thread_priority = true; +boinc_init_options(&options); +``` On Windows, this causes the application to run at normal thread priority, so that the GPU will run at full speed even if the CPUs are loaded. # Termination When the application has completed it must call - - #!c++ - int boinc_finish(int status); - +```c++ +int boinc_finish(int status); +``` `status` is nonzero if an error was encountered. This call does not return. -Do *not* call `exit(0)`. +Do **not** call `exit(0)`. If you do, BOINC will restart the app, which is probably not what you want. Alternatively, if you want to show a message to the user (e.g. because of an error condition that the user can remedy) use - - boinc_finish_message(int status, const char* msg, bool is_notice); - -If *is_notice* is true, the message will be shown as a notice in the GUI +``` +boinc_finish_message(int status, const char* msg, bool is_notice); +``` +If **is_notice** is true, the message will be shown as a notice in the GUI (works with 7.5+ clients; for others, no message will be shown). -# Resolving file names #filenames +# Resolving file names Applications that use named input or output files must call - - #!c++ - int boinc_resolve_filename(char *logical_name, char *physical_name, int len); - +```c++ +int boinc_resolve_filename(char *logical_name, char *physical_name, int len); +``` or - - #!c++ - int boinc_resolve_filename_s(char *logical_name, std::string& physical_name); - +```c++ +### int boinc_resolve_filename_s(char *logical_name, std +string& physical_name); +``` to convert logical file names to physical names. For example, instead of - - #!c++ - f = fopen("my_file", "r"); - +```c++ +f = fopen("my_file", "r"); +``` the application might use - - #!c++ - string resolved_name; - retval = boinc_resolve_filename_s("my_file", resolved_name); - if (retval) fail("can't resolve filename"); - f = boinc_fopen(resolved_name.c_str(), "r"); - +```c++ +string resolved_name; +retval = boinc_resolve_filename_s("my_file", resolved_name); +if (retval) fail("can't resolve filename"); +f = boinc_fopen(resolved_name.c_str(), "r"); +``` -Don't use `boinc_resolve_filename()` for files with the *copy_file* attribute, +Don't use `boinc_resolve_filename()` for files with the **copy_file** attribute, or for temporary files. It must be used for all other input or output files specified in the job templates, or files that are part of the application version. -# I/O wrappers #fopen +# I/O wrappers Applications should replace `fopen()` calls with - - #!c++ - boinc_fopen(char* path, char* mode); - +```c++ +boinc_fopen(char* path, char* mode); +``` This deals with platform-specific problems. On Windows, where security and indexing programs can briefly lock files, @@ -122,11 +118,11 @@ On Windows, where security and indexing programs can briefly lock files, On Unix, where signals can cause `fopen()` to fail with `EINTR`, `boinc_fopen` checks for this and does a few retries; it also sets the 'close-on-exec' flag. -# Checkpointing #checkpointing +# Checkpointing Long jobs may want to periodically write the current state of the computation to disk. -This is known as *checkpointing*. +This is known as **checkpointing**. The checkpoint file must include everything required to restart the computation at the same point. On startup, the application reads the checkpoint file to determine where to begin computation. @@ -137,23 +133,21 @@ Most applications are able to checkpoint only at specific points, e.g. at the end the outer loop. Whan the application is at such a point, it must call - - #!c++ - int boinc_time_to_checkpoint(); - +```c++ +int boinc_time_to_checkpoint(); +``` If this returns nonzero (True) then the application should checkpoint immediately (i.e., write the state file and flush all output files), then call - - #!c++ - void boinc_checkpoint_completed(); - +```c++ +void boinc_checkpoint_completed(); +``` `boinc_time_to_checkpoint()` is fast, so it can be called frequently (hundreds or thousands of times a second). -*boinc_time_to_checkpoint* returns true only when sufficient time +**boinc_time_to_checkpoint** returns true only when sufficient time has passed since the last checkpoint. This minimum interval is the maximum of: @@ -161,9 +155,9 @@ This minimum interval is the maximum of: (e.g. laptop users might want to checkpoint infrequently). * An optional application-supplied, specified by calling - - boinc_set_min_checkpoint_period(int nsecs); - +``` +boinc_set_min_checkpoint_period(int nsecs); +``` If you're using replication, make sure your application generates the same results regardless of where and how often it restarts. @@ -173,64 +167,61 @@ This requires: * If your app uses random numbers, save and restore the state of the RNG. If you use rand(), you can do this by surrounding every boinc_time_to_checkpoint() with the following: - - int x = rand(); - if (boinc_time_to_checkpoint()) { - ... - } - srand(x); - +``` +int x = rand(); +if (boinc_time_to_checkpoint()) { + ... +} +srand(x); +``` Write x to the checkpoint file, and do a srand(x) when restarting from a checkpoint. -# Critical sections #critical_sections +# Critical sections - - #!c++ - void boinc_begin_critical_section(); - void boinc_end_critical_section(); - +```c++ +void boinc_begin_critical_section(); +void boinc_end_critical_section(); +``` Call these around code segments during which you don't want to be suspended or killed by the core client. Since r14694, critical sections are reentrant. This means that you can begin critical section multiple times, -but each `begin` must have a matching `end` call. +but each ```begin``` must have a matching ```end``` call. -*NOTE:* This is done automatically while checkpointing. +**NOTE:** This is done automatically while checkpointing. # Atomic file update To facilitate atomic checkpoint, an application can write to output and state files using the `MFILE` class. - - #!c++ - class MFILE { - public: - int open(char* path, char* mode); - int _putchar(char); - int puts(char*); - int printf(char* format, ...); - size_t write(const void* buf, size_t size, size_t nitems); - int close(); - int flush(); - }; - +```c++ +class MFILE { +public: + int open(char* path, char* mode); + int _putchar(char); + int puts(char*); + int printf(char* format, ...); + size_t write(const void* buf, size_t size, size_t nitems); + int close(); + int flush(); +}; +``` MFILE buffers data in memory and writes to disk only on `flush()` or `close()`. This lets you write output files and state files more or less atomically. -# Reporting progress #progress +# Reporting progress The BOINC Manager displays the percent done of tasks in progress. To keep this display current, an application should periodically call - - #!c++ - boinc_fraction_done(double fraction_done); - +```c++ +boinc_fraction_done(double fraction_done); +``` The `fraction_done` argument is an estimate of the workunit fraction complete (from 0 to 1). This function is fast and can be called frequently (once per second or more). @@ -244,22 +235,22 @@ If your application can supply an accurate fraction done, set the # Timing information - - #!c++ - int boinc_wu_cpu_time(double &cpu_time); - +```c++ +int boinc_wu_cpu_time(double &cpu_time); +``` gets the total CPU time (from the beginning of the work unit, not just since the last restart). - - double boinc_elapsed_time(); - +``` +double boinc_elapsed_time(); +``` returns the elapsed runtime (i.e. wall-clock time during which the job was not suspended) since the start of the current episode. -The elapsed time from earlier episodes is in APP_INIT_DATA::starting_elapsed_time +### The elapsed time from earlier episodes is in APP_INIT_DATA +starting_elapsed_time (only from 6.10+ clients). -# Standalone mode #standalone +# Standalone mode BOINC applications can be run in "standalone" mode for testing, or under the control of the BOINC client. @@ -269,21 +260,19 @@ if the application is running standalone. To determine if the application is running in standalone mode or under the control of the BOINC client, call - - #!c++ - int boinc_is_standalone(void); - +```c++ +int boinc_is_standalone(void); +``` This returns non-zero (True) if the application is running standalone, and zero (False) if the application is running under the control of the BOINC client. -# Registering a timer handler #timer +# Registering a timer handler - - #!c++ - typedef void (*FUNC_PTR)(); - void boinc_register_timer_callback(FUNC_PTR); - +```c++ +typedef void (*FUNC_PTR)(); +void boinc_register_timer_callback(FUNC_PTR); +``` This registers a timer handler function, which will be called once per second. @@ -293,17 +282,16 @@ which will be called once per second. If an application is unable to run because of a transient condition, it should call - - #!c++ - int boinc_temporary_exit(int delay, const char* reason=NULL, bool is_notice=false); - +```c++ +int boinc_temporary_exit(int delay, const char* reason=NULL, bool is_notice=false); +``` This will exit the application and tell the BOINC client to restart it -again in at least *delay* seconds. +again in at least **delay** seconds. (This works with 6.10.25+ client; on other clients, it will potentially restart immediately). -*Reason*, if supplied, is shown to the user as the explanation for the deferral. -If *is_notice* is true, it's shown as a notice +**Reason**, if supplied, is shown to the user as the explanation for the deferral. +If **is_notice** is true, it's shown as a notice (this should be used only for conditions that the user can fix). Examples: