JasPer  4.1.2
Configuration, Initialization, and Shutdown

API References

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()):

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()):

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:

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

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

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.
*/
/*
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_conf_set_allocator(JAS_CAST(std_allocator_t *, &allocator));
/*
Perform global initialization for the JasPer library.
*/
/* Handle the initialization error. */
}
/*
Perform any per-thread initialization for the JasPer library.
*/
/* Handle the initialization error. */
}
/*
Use the JasPer library.
*/
/* Perform any per-thread clean-up for the JasPer library. */
/* Perform global cleanup for the JasPer library. */
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_EXPORT int jas_cleanup_library()
Perform clean up for the JasPer library.
Definition: jas_init.c:636
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_EXPORT void jas_conf_set_multithread(int multithread)
Set the multithreading flag for the library.
Definition: jas_init.c:419
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_EXPORT int jas_cleanup_thread()
Perform per-thread cleanup for the JasPer library.
Definition: jas_init.c:757
JAS_EXPORT void jas_conf_clear()
Configure the JasPer library with the default configuration settings.
Definition: jas_init.c:397
JAS_EXPORT int jas_init_thread()
Perform per-thread initialization for the JasPer library.
Definition: jas_init.c:696
JAS_EXPORT int jas_init_library()
Initialize the JasPer library with the current configuration settings.
Definition: jas_init.c:475
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.
*/
/* Handle the initialization error. */
}
/*
Use the JasPer library.
*/
/* Perform any per-thread clean-up for the JasPer library. */

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. */
/* Handle initialization error. */
}
/* Code that uses the JasPer library (e.g., performing encoding/decoding).
/* Perform per-thread cleanup of the JasPer library. */
/* Code that does not use the JasPer library. */
/* Perform per-thread initialization of the JasPer library. */
/* Handle initialization error. */
}
/* Code that uses the JasPer library (e.g., performing encoding/decoding).
/* Perform per-thread cleanup of the JasPer library. */
/* 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: