Coverage Report

Created: 2026-10-27 06:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libde265/libde265/threads.cc
Line
Count
Source
1
/*
2
 * H.265 video codec.
3
 * Copyright (c) 2013-2014 struktur AG, Dirk Farin <farin@struktur.de>
4
 *
5
 * This file is part of libde265.
6
 *
7
 * libde265 is free software: you can redistribute it and/or modify
8
 * it under the terms of the GNU Lesser General Public License as
9
 * published by the Free Software Foundation, either version 3 of
10
 * the License, or (at your option) any later version.
11
 *
12
 * libde265 is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU Lesser General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Lesser General Public License
18
 * along with libde265.  If not, see <http://www.gnu.org/licenses/>.
19
 */
20
21
#include "threads.h"
22
#include <assert.h>
23
#include <string.h>
24
25
#if defined(_MSC_VER) || defined(__MINGW32__)
26
# include <malloc.h>
27
#elif defined(HAVE_ALLOCA_H)
28
# include <alloca.h>
29
#endif
30
31
32
de265_progress_lock::de265_progress_lock()
33
1.87M
{
34
1.87M
  mProgress.store(0, std::memory_order_relaxed);
35
1.87M
}
36
37
de265_progress_lock::~de265_progress_lock()
38
1.89M
{
39
1.89M
}
40
41
void de265_progress_lock::wait_for_progress(int progress)
42
1
{
43
  // Fast path: acquire-load pairs with the release-store in set_progress()/
44
  // increase_progress() so that everything the signalling thread wrote before
45
  // reaching this progress value is visible once we observe it here.
46
1
  if (mProgress.load(std::memory_order_acquire) >= progress) {
47
1
    return;
48
1
  }
49
50
0
  std::unique_lock<std::mutex> lock(mutex);
51
0
  while (mProgress.load(std::memory_order_acquire) < progress) {
52
0
    cond.wait(lock);
53
0
  }
54
0
}
55
56
void de265_progress_lock::set_progress(int progress)
57
7.00M
{
58
7.00M
  std::unique_lock<std::mutex> lock(mutex);
59
60
7.00M
  if (progress > mProgress.load(std::memory_order_relaxed)) {
61
5.78M
    mProgress.store(progress, std::memory_order_release);
62
63
5.78M
    cond.notify_all();
64
5.78M
  }
65
7.00M
}
66
67
void de265_progress_lock::increase_progress(int progress)
68
5.32k
{
69
5.32k
  std::unique_lock<std::mutex> lock(mutex);
70
71
5.32k
  mProgress.store(mProgress.load(std::memory_order_relaxed) + progress,
72
5.32k
                  std::memory_order_release);
73
5.32k
  cond.notify_all();
74
5.32k
}
75
76
int  de265_progress_lock::get_progress() const
77
712k
{
78
712k
  return mProgress.load(std::memory_order_acquire);
79
712k
}
80
81
82
83
84
#include "libde265/decctx.h"
85
86
#if 0
87
const char* line="--------------------------------------------------";
88
void printblks(const thread_pool* pool)
89
{
90
  int w = pool->tasks[0].data.task_ctb.ctx->current_sps->PicWidthInCtbsY;
91
  int h = pool->tasks[0].data.task_ctb.ctx->current_sps->PicHeightInCtbsY;
92
93
  printf("active threads: %d  queue len: %d\n",pool->num_threads_working,pool->num_tasks);
94
95
  char *const p = (char *)alloca(w * h * sizeof(char));
96
  assert(p != nullptr);
97
  memset(p,' ',w*h);
98
99
  for (int i=0;i<pool->num_tasks;i++) {
100
    int b = 0; //pool->tasks[i].num_blockers;
101
    int x = pool->tasks[i].data.task_ctb.ctb_x;
102
    int y = pool->tasks[i].data.task_ctb.ctb_y;
103
    p[y*w+x] = b+'0';
104
  }
105
106
  for (int i=0;i<pool->num_threads_working;i++) {
107
    int x = pool->ctbx[i];
108
    int y = pool->ctby[i];
109
    p[y*w+x] = '*';
110
  }
111
112
  printf("+%s+\n",line+50-w);
113
  for (int y=0;y<h;y++)
114
    {
115
      printf("|");
116
      for (int x=0;x<w;x++)
117
        {
118
          printf("%c",p[x+y*w]);
119
        }
120
      printf("|\n");
121
    }
122
  printf("+%s+\n",line+50-w);
123
}
124
#endif
125
126
127
static void worker_thread(thread_pool* pool)
128
9.06k
{
129
318k
  while(true) {
130
131
318k
    thread_task* task = nullptr;
132
133
318k
    {
134
318k
      std::unique_lock<std::mutex> lock(pool->mutex);
135
136
      // wait until we can pick a task or until the pool has been stopped
137
138
339k
      for (;;) {
139
        // end waiting if thread-pool has been stopped or we have a task to execute
140
141
339k
        if (pool->stopped || pool->tasks.size()>0) {
142
318k
          break;
143
318k
        }
144
145
        //printf("going idle\n");
146
20.2k
        pool->cond_var.wait(lock);
147
20.2k
      }
148
149
      // if the pool was shut down, end the execution
150
151
318k
      if (pool->stopped) {
152
9.07k
        return;
153
9.07k
      }
154
155
156
      // get a task
157
158
309k
      task = pool->tasks.front();
159
309k
      pool->tasks.pop_front();
160
161
309k
      pool->num_threads_working++;
162
163
      //printblks(pool);
164
309k
    }
165
166
    // execute the task
167
168
0
    task->work();
169
170
    // end processing and check if this was the last task to be processed
171
172
    // TODO: the num_threads_working can probably be an atomic integer
173
309k
    std::unique_lock<std::mutex> lock(pool->mutex);
174
175
309k
    pool->num_threads_working--;
176
309k
  }
177
9.06k
}
178
179
180
de265_error thread_pool::start(int num_threads_to_start)
181
9.07k
{
182
9.07k
  de265_error err = DE265_OK;
183
184
  // limit number of threads to maximum
185
186
9.07k
  if (num_threads_to_start > MAX_THREADS) {
187
0
    num_threads_to_start = MAX_THREADS;
188
0
    err = DE265_WARNING_NUMBER_OF_THREADS_LIMITED_TO_MAXIMUM;
189
0
  }
190
191
9.07k
  num_threads = 0; // will be increased below
192
193
9.07k
  {
194
9.07k
    std::unique_lock<std::mutex> lock(mutex);
195
196
9.07k
    num_threads_working = 0;
197
9.07k
    stopped = false;
198
9.07k
  }
199
200
  // start worker threads
201
202
18.1k
  for (int i=0; i<num_threads_to_start; i++) {
203
9.07k
    thread[i] = std::thread(worker_thread, this);
204
9.07k
    num_threads++;
205
9.07k
  }
206
207
9.07k
  return err;
208
9.07k
}
209
210
211
void thread_pool::stop()
212
9.07k
{
213
9.07k
  {
214
9.07k
    std::unique_lock<std::mutex> lock(mutex);
215
9.07k
    stopped = true;
216
9.07k
  }
217
218
9.07k
  cond_var.notify_all();
219
220
18.1k
  for (int i=0;i<num_threads;i++) {
221
9.07k
    thread[i].join();
222
9.07k
  }
223
9.07k
}
224
225
226
void thread_pool::add_task(thread_task* task)
227
309k
{
228
309k
  std::unique_lock<std::mutex> lock(mutex);
229
230
309k
  if (!stopped) {
231
232
309k
    tasks.push_back(task);
233
234
    // wake up one thread
235
236
309k
    cond_var.notify_one();
237
309k
  }
238
309k
}