JasPer: Configuration, Initialization, and Shutdown

JasPer 3.0.3 |

Configuration, Initialization, and Shutdown

# API References

- Configuration, Initialization, and Shutdown

# Configuration, Initialization, and Shutdown

There are three stages in the setup of the JasPer library at run time:

1. configuration;
2. global (i.e., library-wide) initialization; and
3. per-thread initialization.

These stages of setup are performed in the order listed. Aside from the exceptions noted in this section, code in the JasPer library must not be invoked by a thread prior to per-thread initialization being performed by that thread. Only the following functions may be called prior to the configuration of the JasPer library (via `jas_conf_clear()`):

- `jas_get_total_mem_size()`

The configuration stage initializes the current (run-time) configuration settings for the library. First, the configuration settings are initialized to their default values using the `jas_conf_clear()` function (where these default values are fixed at the time that the library is built). Then, configuration settings may be changed from their defaults (prior to global initialization), if so desired. The following functions may be called after the JasPer library is configured (via `jas_conf_clear()`) but before global initialization is performed (via `jas_init_library()`):

- the `jas_conf_*` family of functions, including functions such as:
  - `jas_conf_clear()`
  - `jas_conf_set_multithread()`
  - `jas_conf_set_allocator()`
  - `jas_conf_set_debug_level()`
  - `jas_conf_set_max_mem_usage()`
  - `jas_conf_set_dec_default_max_samples()`
  - `jas_conf_set_vlogmsgf()`
- `jas_std_allocator_init()`

In order to use JasPer in multiple threads, the multithread flag must be set (to true) during configuration using the `jas_conf_set_multithread()` function.

The global initialization stage initializes the library itself using the current configuration settings. The `jas_init_library()` function performs global initialization (but not configuration). After global initialization is performed, per-thread initialization can then be performed.

The per-thread initialization stage performs any initialization necessary in order to allow a thread to use the library. The `jas_init_thread()` function performs per-thread initialization. Per-thread initialization cannot be performed until after global initialization. After a thread performs per-thread initialization, it is free to use the full API of the library. Aside from the exceptions noted in this section, no function in the library may be invoked by a thread prior to it performing per-thread initialization via `jas_init_thread()`. Per-thread initialization (via `jas_init_thread()`) can be performed at any point during the lifetime of a thread (not necessarily at the start of the thread's lifetime), subject to the constraint that the thread must not use any macros/functions in the JasPer library that require per-thread initialization to have been performed prior to calling `jas_init_thread()`.

The shutdown of the library roughly mirrors the process for library setup and consists of the following two stages:

1. per-thread clean-up
2. global (i.e., library-wide) clean-up

Each thread that has performed per-thread initialization must perform per-thread clean-up prior to global clean-up. Per-thread clean-up is performed by invoking the `jas_cleanup_thread()` function. Global clean-up is performed by invoking the `jas_cleanup_library()` function.

The library cannot be re-initialized (without first being cleaned up). That is, calling `jas_init_library()` more than once without an intervening call to `jas_cleanup_library()` is not allowed. Note, however, that a program can call `jas_init_library()` more than once, provided that the program makes an intervening call to `jas_cleanup_library()`. Similarly, a thread cannot be re-initialized (without first being cleaned up). That is, calling `jas_init_thread()` more than once without an intervening call to `jas_cleanup_thread()` is not allowed. Note, however, that a thread can call `jas_init_thread()` more than once, provided that the thread makes an intervening call to `jas_cleanup_thread()`.

Configuration, global initialization, and global clean-up should be performed on the same thread. That is, `jas_conf_clear()`, `jas_init_library()`, and `jas_cleanup_library()` must all be called from the same thread.

For backward-compatibility with older versions of the library, the `jas_init()` and `jas_cleanup()` functions may also be used for library setup and shutdown. These function have been marked as deprecated, and will be removed in a future version of the library. Also, if these functions are used, JasPer cannot be employed in more than one thread and library configuration parameters cannot be changed from their defaults. The `jas_init()` function can be used (by legacy code) to perform configuration, global initialization, and per-thread initialization for the calling thread. The `jas_init()` function internally calls `jas_conf_clear()` to initialize the configuration settings with their default values, and then invokes `jas_init_library()` and `jas_init_thread()`. Similarly, `jas_cleanup()` can be used (by legacy code) to perform per-thread cleanup for the calling thread and global cleanup.

# Library State

The JasPer library has the notion of a context. A context is used to store certain state used by the library. There can be multiple contexts in use at any given time. From the library user's point of view, a context is specified using an opaque handle. The type of this handle is `jas_context_t`. A handle with the special value of 0 does not correspond to a valid context. It is analogous to a null pointer.

The JasPer library allows the current context to be set independently for each thread. That is, the current context is a per-thread setting. When a thread is initialized, a single context is automatically created, which is referred to as the default context, and the current context for the thread is set to this default context. A context cannot be shared by more than one thread, as this would lead to data races and other synchronization problems.

The JasPer library has two types of state:

1. Global state. That is, state that is library wide.
2. Per-context state. That is, state that only applies to a particular context.

Most state maintained by the library is in the form of per-context state. This is motivated by the desire to minimize the sharing of state between threads, which would require locking/synchronization. The global state for the library includes:

- the memory allocator to be used by the library
- the maximum amount of memory that the library is permitted to use
- certain configuration settings that are used as default values when creating/initializing contexts

The per-context state includes:

- the debug level
- the vlogmsgf function to be used for logging error/warning/informational messages
- the image format table
- the maximum number of samples in an image that a decoder is allowed to process

# Contexts

Contexts can be created and destroyed with the following functions:

- `jas_context_create()`
- `jas_context_destroy()`

The current context for the calling thread can be set/queried with the following functions:

- `jas_get_context()`
- `jas_set_context()`

The various per-context settings can be set/queried with the following functions:

- `jas_set_debug_level()`
- `jas_get_debug_level()`
- `jas_set_dec_default_max_samples()`
- `jas_get_dec_default_max_samples()`
- `jas_set_vlogmsgf()`
- `jas_get_vlogmsgf()`

# Example of Code for Library Setup and Shutdown

Setup and shutdown of the library would typically be performed in the main thread of the application using code resembling the following:

/*
Configure the library using the default configuration settings.
*/
jas_conf_clear();
/*
Change any configuration parameters for which defaults are not suitable
by using the jas_conf_* family of functions.
An example of this type of code follows.
*/
static jas_std_allocator_t allocator;
jas_std_allocator_init(&allocator);
jas_conf_set_allocator(JAS_CAST(std_allocator_t *, &allocator));
jas_conf_set_max_mem_usage(10000000);
jas_conf_set_multithread(true);
/*
Perform global initialization for the JasPer library.
*/
if (jas_init_library()) {
/* Handle the initialization error. */
}
/*
Perform any per-thread initialization for the JasPer library.
*/
if (jas_init_thread()) {
/* Handle the initialization error. */
}
/*
Use the JasPer library.
*/
/* Perform any per-thread clean-up for the JasPer library. */
jas_cleanup_thread();
/* Perform global cleanup for the JasPer library. */
jas_cleanup_library();
jas_std_allocator_init
JAS_EXPORT void jas_std_allocator_init(jas_std_allocator_t *allocator)
Initialize a memory allocator that uses malloc and related functions for managing memory.
Definition: jas_malloc.c:262
jas_cleanup_library
JAS_EXPORT int jas_cleanup_library()
Perform clean up for the JasPer library.
Definition: jas_init.c:636
jas_conf_set_allocator
JAS_EXPORT void jas_conf_set_allocator(jas_allocator_t *allocator)
Set the memory allocator to be used by the library.
Definition: jas_init.c:425
jas_conf_set_multithread
JAS_EXPORT void jas_conf_set_multithread(int multithread)
Set the multithreading flag for the library.
Definition: jas_init.c:419
jas_conf_set_max_mem_usage
JAS_EXPORT void jas_conf_set_max_mem_usage(size_t max_mem)
Set the maximum amount of memory that can be used by the library (assuming the allocator wrapper is n...
Definition: jas_init.c:445
jas_cleanup_thread
JAS_EXPORT int jas_cleanup_thread()
Perform per-thread cleanup for the JasPer library.
Definition: jas_init.c:757
jas_conf_clear
JAS_EXPORT void jas_conf_clear()
Configure the JasPer library with the default configuration settings.
Definition: jas_init.c:397
jas_init_thread
JAS_EXPORT int jas_init_thread()
Perform per-thread initialization for the JasPer library.
Definition: jas_init.c:696
jas_init_library
JAS_EXPORT int jas_init_library()
Initialize the JasPer library with the current configuration settings.
Definition: jas_init.c:475
jas_std_allocator_t
The standard library allocator (i.e., a wrapper for malloc and friends).
Definition: jas_malloc.h:143

In the case of an application where the JasPer library is used in more than one thread, each additional thread would need to perform per-thread initialization (via `jas_init_thread()`) before using the library. Also, each additional thread would need to perform per-thread cleanup (via `jas_cleanup_thread()`) when the use of the library is no longer needed. For each thread, the code for this might resemble something like the following:

/*
Perform any per-thread initialization for the JasPer library.
*/
if (jas_init_thread()) {
/* Handle the initialization error. */
}
/*
Use the JasPer library.
*/
/* Perform any per-thread clean-up for the JasPer library. */
jas_cleanup_thread();

When practical, it is probably preferable (for reasons of efficiency) to invoke `jas_init_thread()` and `jas_cleanup_thread()` only once in the lifetime of a thread. In some cases, this may be difficult to do, due to the structure of the application code. In such situations, one could simply wrap code using the JasPer library in calls to `jas_init_thread()` and `jas_cleanup_thread()`. As explained earlier, this is valid to do. For example, code like that shown in the example below is valid (assuming that the global initialization of the JasPer library has already been performed).

/* Code that does not use the JasPer library. */
/* Perform per-thread initialization of the JasPer library. */
if (jas_init_thread()) {
/* Handle initialization error. */
}
/* Code that uses the JasPer library (e.g., performing encoding/decoding).
/* Perform per-thread cleanup of the JasPer library. */
jas_cleanup_thread();
/* Code that does not use the JasPer library. */
/* Perform per-thread initialization of the JasPer library. */
if (jas_init_thread()) {
/* Handle initialization error. */
}
/* Code that uses the JasPer library (e.g., performing encoding/decoding).
/* Perform per-thread cleanup of the JasPer library. */
jas_cleanup_thread();
/* Code that does not use the JasPer library. */

# Additional Examples of Library Setup

Some additional examples of using the `jas_conf_clear()`, `jas_init_library()`, `jas_init_thread()`, `jas_cleanup_thread()`, and `jas_cleanup_library()`, functions (as well as the `jas_init()` and `jas_cleanup()` functions) can be found in the source code for the application programs `jasper`, `imginfo`, and `imgcmp`. Moreover, the application program `multithread` is an example of a program that uses the JasPer library in multiple threads.

# Memory Allocators and the Allocator Wrapper

The library provides a simple interface for memory allocators. This is provided through the `jas_allocator_t` type. An allocator object resides in memory managed by the library user. If the library user invokes `jas_cleanup_library()` via `atexit()`, then the allocator should obviously not be allocated on the stack. (The `jas_cleanup_library()` function will use the allocator in order to free memory previously allocated by the library.)

The `jas_std_allocator_init()` function provides a way to create an allocator that uses `malloc()` and related functions from the C standard library.

The JasPer library does not directly use the allocator provided by the library user. It instead uses this allocator indirectly through a wrapper. The allocator wrapper is a pseudo-allocator. That is, it does not actually allocate memory directly but rather delegates the memory allocation operations to another allocator (namely, the one specified by the library user). The allocator wrapper tracks the amount of memory used by the allocator to which it delegates. This eliminates the need for the library user's allocator to track this information itself.

As long as the allocator wrapper functionality is enabled, the JasPer library will track how much memory is being used by the allocator in order to allow a limit to be imposed on memory usage. The allocator wrapper composes with the allocator selected by the library user, as explained above. So, this memory limiting functionality is available even when the library user provides a custom allocator that does not itself track memory usage.

Although `jas_malloc()`, `jas_realloc()`, `jas_free()` and other related functions internally use the allocator provided by the library user for all memory allocations, this does not imply that pointers returned by `jas_malloc()` (and related functions) can be used with the library user's allocator directly. For this reason, it is important to use the `jas_free()` function to free memory allocated by `jas_malloc()` and friends (and not attempt to directly invoke the underlying custom allocator provided by the library user).

An allocator provides functions with the following signatures and semantics:

- `void (*cleanup)(jas_allocator_t *allocator);`

  This function performs a clean-up operation, which cleans up the allocator when it is no longer needed. This operation should free any resources associated with the allocator. The allocator cannot be used after the clean-up operation is performed. This function pointer may be null, in which case the clean-up operation is treated as a no-op.

- `void *(*alloc)(jas_allocator_t *allocator, size_t size);`

  This function performs a memory-allocation operation, and has behavior similar to `malloc()`.

- `void (*free)(jas_allocator_t *allocator, void *pointer)`;

  This function performs a memory-deallocation operation, and has behavior similar to `free()`.

- `void *(*realloc)(jas_allocator_t *allocator, void *pointer, size_t new_size);`

  This function performs a memory-reallocation operation, and has behavior similar to `realloc()`.

# Logging

All error, warning, informational, and debugging messages are normally generated via the logging interface provided by the library. The library user can specify a special function used to generate formatted logging messages. The library user can therefore control where messages are directed. The function has the following signature:

- `int (*vlogprintf)(jas_logtype_t type, const char *format, va_list ap);`

  The function formats and outputs a log message. The interface of this function is somewhat similar to vprintf. In addition to a format string and items used for formatting, the function also takes a specification of the type of message being generated (e.g., error, warning, etc.).

This function is used in order to implement functions such as:

- `jas_vlogmsgf()`
- `jas_logprintf()`
- `jas_logerrorf()`
- `jas_logwarnf()`
- `jas_loginfof()`
- `jas_logdebugf()`