summaryrefslogtreecommitdiffstats
path: root/third_party/jpeg-xl/lib/threads/thread_parallel_runner.cc
blob: 558c9dbe42303c5607a038fe2d56d2b90b3c9a60 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
// Copyright (c) the JPEG XL Project Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

#include <jxl/memory_manager.h>
#include <jxl/parallel_runner.h>
#include <jxl/thread_parallel_runner.h>
#include <string.h>

#include <cstdint>
#include <cstdlib>
#include <thread>

#include "lib/threads/thread_parallel_runner_internal.h"

namespace {

// Default JxlMemoryManager using malloc and free for the jpegxl_threads
// library. Same as the default JxlMemoryManager for the jpegxl library
// itself.

// Default alloc and free functions.
void* ThreadMemoryManagerDefaultAlloc(void* opaque, size_t size) {
  return malloc(size);
}

void ThreadMemoryManagerDefaultFree(void* opaque, void* address) {
  free(address);
}

// Initializes the memory manager instance with the passed one. The
// MemoryManager passed in |memory_manager| may be NULL or contain NULL
// functions which will be initialized with the default ones. If either alloc
// or free are NULL, then both must be NULL, otherwise this function returns an
// error.
bool ThreadMemoryManagerInit(JxlMemoryManager* self,
                             const JxlMemoryManager* memory_manager) {
  if (memory_manager) {
    *self = *memory_manager;
  } else {
    memset(self, 0, sizeof(*self));
  }
  bool is_default_alloc = (self->alloc == nullptr);
  bool is_default_free = (self->free == nullptr);
  if (is_default_alloc != is_default_free) {
    return false;
  }
  if (is_default_alloc) self->alloc = ThreadMemoryManagerDefaultAlloc;
  if (is_default_free) self->free = ThreadMemoryManagerDefaultFree;

  return true;
}

void* ThreadMemoryManagerAlloc(const JxlMemoryManager* memory_manager,
                               size_t size) {
  return memory_manager->alloc(memory_manager->opaque, size);
}

void ThreadMemoryManagerFree(const JxlMemoryManager* memory_manager,
                             void* address) {
  memory_manager->free(memory_manager->opaque, address);
}

}  // namespace

JxlParallelRetCode JxlThreadParallelRunner(
    void* runner_opaque, void* jpegxl_opaque, JxlParallelRunInit init,
    JxlParallelRunFunction func, uint32_t start_range, uint32_t end_range) {
  return jpegxl::ThreadParallelRunner::Runner(
      runner_opaque, jpegxl_opaque, init, func, start_range, end_range);
}

/// Starts the given number of worker threads and blocks until they are ready.
/// "num_worker_threads" defaults to one per hyperthread. If zero, all tasks
/// run on the main thread.
void* JxlThreadParallelRunnerCreate(const JxlMemoryManager* memory_manager,
                                    size_t num_worker_threads) {
  JxlMemoryManager local_memory_manager;
  if (!ThreadMemoryManagerInit(&local_memory_manager, memory_manager))
    return nullptr;

  void* alloc = ThreadMemoryManagerAlloc(&local_memory_manager,
                                         sizeof(jpegxl::ThreadParallelRunner));
  if (!alloc) return nullptr;
  // Placement new constructor on allocated memory
  jpegxl::ThreadParallelRunner* runner =
      new (alloc) jpegxl::ThreadParallelRunner(num_worker_threads);
  runner->memory_manager = local_memory_manager;

  return runner;
}

void JxlThreadParallelRunnerDestroy(void* runner_opaque) {
  jpegxl::ThreadParallelRunner* runner =
      reinterpret_cast<jpegxl::ThreadParallelRunner*>(runner_opaque);
  if (runner) {
    JxlMemoryManager local_memory_manager = runner->memory_manager;
    // Call destructor directly since custom free function is used.
    runner->~ThreadParallelRunner();
    ThreadMemoryManagerFree(&local_memory_manager, runner);
  }
}

// Get default value for num_worker_threads parameter of
// InitJxlThreadParallelRunner.
size_t JxlThreadParallelRunnerDefaultNumWorkerThreads() {
  return std::thread::hardware_concurrency();
}