s/THREAD_MODE_ABOVE_NORMAL/THREAD_PRIORITY_ABOVE_NORMAL/
Thanks to Sylvie Alexandre for noticing and searching this.
(cherry picked from commit ebc3ef3c5e)
... which is equivalent to gimp_parallel_run_async_independent(),
except that it takes an additional "priority" parameter, which
specifies the task's priority, with 0 being the default priority,
and lower values indicating higher priority. Unlike
gimp_parallel_run_async_full(), the priority parameter doesn't
directly control the task's priority in a queue, but rather, we use
it to control the priority of the task's dedicated thread, on
supported platforms (previously, all independent async tasks would
run with low priority.)
Use low priority when loading fonts, which can take a long time, to
keep the existing behavior.
(cherry picked from commit fa2e4dcce0)
When an async that was created through
gimp_parallel_run_async[_full](), and whose execution is still
pending, is being waited-upon, maximize its priority so that it
gets executed before all other pending asyncs.
Note that we deliberately don't simply execute the async in the
calling thread in this case, to allow timed-waits to fail (which is
especially important for gimp_wait()).
(cherry picked from commit 62baffed98)
Fix indentation in gimp-parallel.{cc,h}.
Remove unused typedefs in gimp-parallel.h.
s/Gimp/Gegl/ in function-type cast in gimphistogram.c.
(cherry picked from commit 05a4437d9a)
The parallel_distribute() family of functions has been migrated to
GEGL. Remove the gimp_parallel_distribute() functions from
gimp-parallel, and replace all uses of these functions with the
corresponding gegl_parallel_distrubte() functions.
(cherry picked from commit 2736cee577)
In the gimp_parallel_run_async() family of functions, allow the
async callback to return without completing the async operation, in
which case the callback will be called again, until the operation
is either completed, or canceled, in which case it is aborted
(previously, returning from the callback without completing the
operation would cause it to be aborted.) It is guaranteed that all
operations of the same priority will get a chance to run, even if
some of them contuinuosly return without completing.
This allows potentially time-consuming operations to yield
execution in favor of other same-priority operations, and, in
particular, of higher-priority operations, to avoid priority
inversion. Essentially, this allows a simple form of cooperative
multitasking among async operations.
(cherry picked from commit 4969d75785)
When shutting-down gimp-parallel, cancel and/or abort any ongoing
and queued async operations, instead of finishing them (async
operations that already started executing will be canceled, but
execution will be blocked until they're finished.) This is
especially important since we're shutting down gimp-parallel before
the destruction of data factories. This commit causes any ongoing
async operations of the factories to be canceled on shutdown,
rather than waiting for them to finish normally.
(cherry picked from commit e46fdc714e)
In gimp-parallel, always flush the async-operations queue (by
executing all remaining operations on the caller thread) when
setting the async-pool thread count to 0 (as happens when setting
GEGL_THREADS=1, per the previous commit,) and not only when
shutting GIMP down. Otherwise, pending asynchronous operations
can "get lost" when setting GEGL_THREADS to 1.
Additionally, in gimp_gegl_init(), initialize gimp-parallel before
before connecting to GimpGeglConfig's "notify::num-processors"
signal, so that the number of async threads is set *before*
GEGL_THREADS, in order to avoid setting GEGL_THREADS to 1 while
async operations are still executing.
Also, allow setting the number of gimp-parallel-distribute threads
while a gimp-parallel-distribute function is running (which can
happen if gimp-parallel-distribute is used in an async operation,
as is the case for histogram calculation), by waiting for the
parallel-distribute function to finish before setting the number of
threads.
(cherry picked from commit 432a884715)
When GEGL_THREADS=1, concurrent access to the same buffer is not
safe, which can result in errors if asynchronous operations are
allowed to run in parallel to the main thread (see
https://gitlab.gnome.org/GNOME/gimp/issues/1721#note_265898.)
Disable parallel execution of asynchronous operations when
GEGL_THREADS=1 for now, to fix this. Ultimately, GEGL should be
able to remain thread-safe even when GEGL_THREADS=1. Note that we
want to execute asynchronous operations on a separate thread even
when GEGL_THREADS=1, since the goal here is mainly to avoid
blocking the main thread during their execution, rather than
speeding their execution up (in particular, it's benecifical to run
asynchronous operations in parallel even on a single-core machine,
while parallelizing GEGL operations generally isn't.)
(cherry picked from commit 408540659f)
Remove the "independent" parameter of gimp_parallel_run_async(),
and have the function always execute the passed callback in the
shared async thread-pool.
Add a new gimp_parallel_run_async_full() function, taking, in
addition to a callback and a data pointer:
- A priority value, controlling the priority of the callback in
the async thread-pool queue. 0 is the default priority (used
by gimp_parallel_run_async()), negative values have higher
priority, and positive values have lower priority.
- A destructor function for the data pointer. This function is
called to free the user data in case the async operation is
canceled before execution of the callback function begins, and
the operation is dropped from the queue and aborted without
executing the callback. Note that if the callback *is*
executed, the destructor is *not* used -- it's the callback's
responsibility to free/recycle the user data.
Add a separate gimp_parallel_run_async_independent() function,
taking the same parameters, and executing the passed callback in
an independent thread, rather than the thread pool. This function
doesn't take a priority value or a destructor (and there's no
corresponding "_full()" variant that does), since they're pointless
for independent threads.
Adapt the rest of the code to the changes.
(cherry picked from commit b74e600c12)
In gimp_parallel_run_async(), lower the priority of threads
executing independent async operations. Independent operations
are generally potentially long-standing background tasks, which we
don't want to bog down the rest of the program.
This is currently only implemented on Linux and Windows.
In gimp_parallel_run_async(), when aborting a GimpAsync operation
in reponse to its "cancel" signal, properly clean up internal data
attached to the object, to avoid use-after-free if the signal is
emitted again.
(cherry picked from commit 3fa4c01bcf)
Add a boolean "independent" parameter to gimp_parallel_run_async().
When FALSE, the passed function is run in the shared async thread
pool; when TRUE, the passed function is run in an independent
thread.
Generally, async operations should run in the async pool, however,
it might be desirable to run long-standing operations, especially
ones that can't be canceled, in independent threads. This avoids
stalling quicker operations, and shutdown.
Adapt the rest of the code for the change. In particular,
initialize the font cache in an independent thread.
(cherry picked from commit ad8add6808)
In gimp_parallel_run_async(), connect to the returned GimpAsync's
"cancel" signal, and abort the operation in response if it's still
enqueued, i.e., if its execution hasn't started yet.
(cherry picked from commit 3958ffbe50)
... which runs a user-provided function asynchronously, returning a
corresponding GimpAsync object. This can be used to execute code
off the main thread, using the GimpAsync object to synchronize as
necessary.
Note that while the code allows for running multiple asynchronous
functions in parallel in a thread pool, we currently limit the pool
to a single thread, queueing overlapping async function, since we
have no use for parallel asynchronous functions at the moment.
Add gimp-parallel.[cc,h], which provides a set of parallel
algorithms.
These currently include:
- gimp_parallel_distribute(): Calls a callback function in
parallel on multiple threads, passing it the current thread
index, and the total number of threads. Allows specifying the
maximal number of threads used.
- gimp_parallel_distribute_range(): Splits a range of integers
between multiple threads, passing the sub-range to a callback
function. Allows specifying the minimal sub-range size.
- gimp_parallel_distribute_area(): Splits a rectangular area
between multiple threads, passing the sub-area to a callback
function. Allows specifying the minimal sub-area.
The callback function is passed using an appropriately-typed
function pointer, and a user-data pointer. Additionally, when used
in a C++ file, each of the above functions has an overloaded
template version, taking the callback through a generic parameter,
without a user-data pointer, which allows using function objects.