LCOV - code coverage report
Current view: top level - src - thread.c (source / functions) Coverage Total Hit
Test: colopresso Coverage Report Lines: 84.3 % 51 43
Test Date: 2026-02-16 05:23:27 Functions: 100.0 % 5 5
Legend: Lines: hit not hit

            Line data    Source code
       1              : /*
       2              :  * SPDX-License-Identifier: GPL-3.0-or-later
       3              :  *
       4              :  * This file is part of colopresso
       5              :  *
       6              :  * Copyright (C) 2025-2026 COLOPL, Inc.
       7              :  *
       8              :  * Author: Go Kudo <g-kudo@colopl.co.jp>
       9              :  * Developed with AI (LLM) code assistance. See `NOTICE` for details.
      10              :  */
      11              : 
      12              : #include <colopresso.h>
      13              : #include <colopresso/portable.h>
      14              : 
      15              : #include "internal/log.h"
      16              : #include "internal/threads.h"
      17              : 
      18              : #if COLOPRESSO_ENABLE_THREADS
      19              : 
      20              : #include <stdlib.h>
      21              : 
      22              : typedef struct {
      23              :   parallel_func_t func;
      24              :   void *context;
      25              :   uint32_t start_index;
      26              :   uint32_t end_index;
      27              : } thread_work_t;
      28              : 
      29           47 : static void *thread_worker(void *arg) {
      30           47 :   thread_work_t *work = (thread_work_t *)arg;
      31              : 
      32           47 :   if (work && work->func) {
      33           47 :     work->func(work->context, work->start_index, work->end_index);
      34              :   }
      35              : 
      36           47 :   return NULL;
      37              : }
      38              : 
      39           20 : uint32_t cpres_get_default_thread_count(void) {
      40           20 :   uint32_t cpu_count = colopresso_get_cpu_count();
      41           20 :   uint32_t half = (uint32_t)(cpu_count / 2);
      42              : 
      43           20 :   return half > 0 ? half : 1;
      44              : }
      45              : 
      46            1 : uint32_t cpres_get_max_thread_count(void) { return colopresso_get_cpu_count(); }
      47              : 
      48            1 : bool cpres_is_threads_enabled(void) { return true; }
      49              : 
      50           50 : bool colopresso_parallel_for(uint32_t use_threads, uint32_t total_items, parallel_func_t func, void *context) {
      51              :   colopresso_thread_t *threads;
      52              :   thread_work_t *works;
      53              :   uint32_t thread_count, chunk_size, remainder, start, end, i;
      54              :   int rc;
      55           50 :   bool success = true;
      56              : 
      57           50 :   if (!func || total_items == 0) {
      58            2 :     return false;
      59              :   }
      60              : 
      61           48 :   thread_count = use_threads > 0 ? use_threads : cpres_get_default_thread_count();
      62           48 :   if (thread_count > total_items) {
      63            1 :     thread_count = total_items;
      64              :   }
      65              : 
      66           48 :   if (thread_count <= 1) {
      67           27 :     func(context, 0, total_items);
      68           27 :     return true;
      69              :   }
      70              : 
      71           21 :   threads = (colopresso_thread_t *)malloc(sizeof(colopresso_thread_t) * thread_count);
      72           21 :   works = (thread_work_t *)malloc(sizeof(thread_work_t) * thread_count);
      73           21 :   if (!threads || !works) {
      74            0 :     free(threads);
      75            0 :     free(works);
      76            0 :     func(context, 0, total_items);
      77              : 
      78            0 :     return true;
      79              :   }
      80              : 
      81           21 :   chunk_size = total_items / thread_count;
      82           21 :   remainder = total_items % thread_count;
      83           21 :   start = 0;
      84              : 
      85           68 :   for (i = 0; i < thread_count; ++i) {
      86           47 :     end = start + chunk_size;
      87           47 :     if (i < remainder) {
      88            0 :       ++end;
      89              :     }
      90              : 
      91           47 :     works[i].func = func;
      92           47 :     works[i].context = context;
      93           47 :     works[i].start_index = start;
      94           47 :     works[i].end_index = end;
      95              : 
      96           47 :     rc = colopresso_thread_create(&threads[i], NULL, thread_worker, &works[i]);
      97           47 :     if (rc != 0) {
      98            0 :       colopresso_log(CPRES_LOG_LEVEL_WARNING, "Threads: colopresso_thread_create failed (rc=%d) - falling back to inline execution", rc);
      99            0 :       works[i].func(works[i].context, works[i].start_index, works[i].end_index);
     100            0 :       threads[i] = (colopresso_thread_t)NULL;
     101              :     }
     102              : 
     103           47 :     start = end;
     104              :   }
     105              : 
     106           68 :   for (i = 0; i < thread_count; ++i) {
     107           47 :     if (threads[i] != (colopresso_thread_t)NULL) {
     108           47 :       colopresso_thread_join(threads[i], NULL);
     109              :     }
     110              :   }
     111              : 
     112           21 :   free(threads);
     113           21 :   free(works);
     114              : 
     115           21 :   return success;
     116              : }
     117              : 
     118              : #else
     119              : 
     120              : uint32_t cpres_get_default_thread_count(void) { return 1; }
     121              : uint32_t cpres_get_max_thread_count(void) { return 1; }
     122              : bool cpres_is_threads_enabled(void) { return false; }
     123              : 
     124              : bool colopresso_parallel_for(uint32_t use_threads, uint32_t total_items, parallel_func_t func, void *context) {
     125              :   if (!func || total_items == 0) {
     126              :     return false;
     127              :   }
     128              : 
     129              :   func(context, 0, total_items);
     130              : 
     131              :   return true;
     132              : }
     133              : 
     134              : #endif
        

Generated by: LCOV version 2.0-1