Coverage Report

Created: 2026-10-17 06:53

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/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
0
{
34
0
  mProgress.store(0, std::memory_order_relaxed);
35
0
}
36
37
de265_progress_lock::~de265_progress_lock()
38
0
{
39
0
}
40
41
void de265_progress_lock::wait_for_progress(int progress)
42
0
{
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
0
  if (mProgress.load(std::memory_order_acquire) >= progress) {
47
0
    return;
48
0
  }
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
0
{
58
0
  std::unique_lock<std::mutex> lock(mutex);
59
60
0
  if (progress > mProgress.load(std::memory_order_relaxed)) {
61
0
    mProgress.store(progress, std::memory_order_release);
62
63
0
    cond.notify_all();
64
0
  }
65
0
}
66
67
void de265_progress_lock::increase_progress(int progress)
68
0
{
69
0
  std::unique_lock<std::mutex> lock(mutex);
70
71
0
  mProgress.store(mProgress.load(std::memory_order_relaxed) + progress,
72
0
                  std::memory_order_release);
73
0
  cond.notify_all();
74
0
}
75
76
int  de265_progress_lock::get_progress() const
77
0
{
78
0
  return mProgress.load(std::memory_order_acquire);
79
0
}
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
0
{
129
0
  while(true) {
130
131
0
    thread_task* task = nullptr;
132
133
0
    {
134
0
      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
0
      for (;;) {
139
        // end waiting if thread-pool has been stopped or we have a task to execute
140
141
0
        if (pool->stopped || pool->tasks.size()>0) {
142
0
          break;
143
0
        }
144
145
        //printf("going idle\n");
146
0
        pool->cond_var.wait(lock);
147
0
      }
148
149
      // if the pool was shut down, end the execution
150
151
0
      if (pool->stopped) {
152
0
        return;
153
0
      }
154
155
156
      // get a task
157
158
0
      task = pool->tasks.front();
159
0
      pool->tasks.pop_front();
160
161
0
      pool->num_threads_working++;
162
163
      //printblks(pool);
164
0
    }
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
0
    std::unique_lock<std::mutex> lock(pool->mutex);
174
175
0
    pool->num_threads_working--;
176
0
  }
177
0
}
178
179
180
de265_error thread_pool::start(int num_threads_to_start)
181
0
{
182
0
  de265_error err = DE265_OK;
183
184
  // limit number of threads to maximum
185
186
0
  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
0
  num_threads = 0; // will be increased below
192
193
0
  {
194
0
    std::unique_lock<std::mutex> lock(mutex);
195
196
0
    num_threads_working = 0;
197
0
    stopped = false;
198
0
  }
199
200
  // start worker threads
201
202
0
  for (int i=0; i<num_threads_to_start; i++) {
203
0
    thread[i] = std::thread(worker_thread, this);
204
0
    num_threads++;
205
0
  }
206
207
0
  return err;
208
0
}
209
210
211
void thread_pool::stop()
212
0
{
213
0
  {
214
0
    std::unique_lock<std::mutex> lock(mutex);
215
0
    stopped = true;
216
0
  }
217
218
0
  cond_var.notify_all();
219
220
0
  for (int i=0;i<num_threads;i++) {
221
0
    thread[i].join();
222
0
  }
223
0
}
224
225
226
void thread_pool::add_task(thread_task* task)
227
0
{
228
0
  std::unique_lock<std::mutex> lock(mutex);
229
230
0
  if (!stopped) {
231
232
0
    tasks.push_back(task);
233
234
    // wake up one thread
235
236
0
    cond_var.notify_one();
237
0
  }
238
0
}