LCOV - code coverage report
Current view: top level - lib - lwan-job.c (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 39 70 55.7 %
Date: 2023-04-18 16:19:03 Functions: 4 6 66.7 %

          Line data    Source code
       1             : /*
       2             :  * lwan - web server
       3             :  * Copyright (c) 2012, 2013 L. A. F. Pereira <l@tia.mat.br>
       4             :  *
       5             :  * This program is free software; you can redistribute it and/or
       6             :  * modify it under the terms of the GNU General Public License
       7             :  * as published by the Free Software Foundation; either version 2
       8             :  * of the License, or any later version.
       9             :  *
      10             :  * This program is distributed in the hope that it will be useful,
      11             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      12             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13             :  * GNU General Public License for more details.
      14             :  *
      15             :  * You should have received a copy of the GNU General Public License
      16             :  * along with this program; if not, write to the Free Software
      17             :  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
      18             :  */
      19             : 
      20             : #define _GNU_SOURCE
      21             : #include <assert.h>
      22             : #include <errno.h>
      23             : #include <ioprio.h>
      24             : #include <pthread.h>
      25             : #include <sched.h>
      26             : #include <stdbool.h>
      27             : #include <stdlib.h>
      28             : #include <sys/time.h>
      29             : #include <unistd.h>
      30             : 
      31             : #include "lwan-private.h"
      32             : #include "lwan-status.h"
      33             : #include "list.h"
      34             : 
      35             : struct job {
      36             :     struct list_node jobs;
      37             :     bool (*cb)(void *data);
      38             :     void *data;
      39             : };
      40             : 
      41             : static pthread_t self;
      42             : static pthread_mutex_t queue_mutex = PTHREAD_MUTEX_INITIALIZER;
      43             : static bool running = false;
      44             : static struct list_head jobs;
      45             : 
      46             : static pthread_mutex_t job_wait_mutex = PTHREAD_MUTEX_INITIALIZER;
      47             : static pthread_cond_t job_wait_cond = PTHREAD_COND_INITIALIZER;
      48             : 
      49             : static void
      50          97 : timedwait(bool had_job)
      51             : {
      52             :     static int secs = 1;
      53             :     struct timeval now;
      54             : 
      55          97 :     if (had_job)
      56           2 :         secs = 1;
      57          95 :     else if (secs <= 15)
      58          95 :         secs++;
      59             : 
      60          97 :     gettimeofday(&now, NULL);
      61             : 
      62          97 :     struct timespec rgtp = { now.tv_sec + secs, now.tv_usec * 1000 };
      63          97 :     pthread_cond_timedwait(&job_wait_cond, &job_wait_mutex, &rgtp);
      64           5 : }
      65             : 
      66          92 : void lwan_job_thread_main_loop(void)
      67             : {
      68             :     /* Idle priority for the calling thread.   Magic value of `7` obtained from
      69             :      * sample program in linux/Documentation/block/ioprio.txt.  This is a no-op
      70             :      * on anything but Linux.  */
      71          92 :     ioprio_set(IOPRIO_WHO_PROCESS, 0, IOPRIO_PRIO_VALUE(IOPRIO_CLASS_IDLE, 7));
      72             : 
      73          92 :     lwan_set_thread_name("job");
      74             : 
      75          92 :     if (pthread_mutex_lock(&job_wait_mutex))
      76           0 :         lwan_status_critical("Could not lock job wait mutex");
      77             :     
      78          97 :     while (running) {
      79          97 :         bool had_job = false;
      80             : 
      81          97 :         if (LIKELY(!pthread_mutex_lock(&queue_mutex))) {
      82             :             struct job *job;
      83             : 
      84         291 :             list_for_each(&jobs, job, jobs)
      85         194 :                 had_job |= job->cb(job->data);
      86             : 
      87          97 :             pthread_mutex_unlock(&queue_mutex);
      88             :         }
      89             : 
      90          97 :         timedwait(had_job);
      91             :     }
      92             : 
      93           0 :     if (pthread_mutex_unlock(&job_wait_mutex))
      94           0 :         lwan_status_critical("Could not lock job wait mutex");
      95           0 : }
      96             : 
      97          92 : void lwan_job_thread_init(void)
      98             : {
      99          92 :     assert(!running);
     100             : 
     101          92 :     lwan_status_debug("Initializing low priority job thread");
     102             : 
     103          92 :     list_head_init(&jobs);
     104             : 
     105          92 :     self = pthread_self();
     106          92 :     running = true;
     107             : 
     108             : #ifdef SCHED_IDLE
     109          92 :     struct sched_param sched_param = {
     110             :         .sched_priority = 0
     111             :     };
     112          92 :     if (pthread_setschedparam(self, SCHED_IDLE, &sched_param) < 0)
     113           0 :         lwan_status_perror("pthread_setschedparam");
     114             : #endif  /* SCHED_IDLE */
     115          92 : }
     116             : 
     117           0 : void lwan_job_thread_shutdown(void)
     118             : {
     119           0 :     lwan_status_debug("Shutting down job thread");
     120             : 
     121           0 :     if (LIKELY(!pthread_mutex_lock(&queue_mutex))) {
     122             :         struct job *node, *next;
     123             :         int r;
     124             : 
     125           0 :         list_for_each_safe(&jobs, node, next, jobs) {
     126           0 :             list_del(&node->jobs);
     127           0 :             free(node);
     128             :         }
     129           0 :         running = false;
     130             : 
     131           0 :         pthread_cond_signal(&job_wait_cond);
     132             : 
     133           0 :         r = pthread_join(self, NULL);
     134           0 :         if (r) {
     135           0 :             errno = r;
     136           0 :             lwan_status_perror("pthread_join");
     137             :         }
     138             : 
     139           0 :         pthread_mutex_unlock(&queue_mutex);
     140             :     }
     141           0 : }
     142             : 
     143         192 : void lwan_job_add(bool (*cb)(void *data), void *data)
     144             : {
     145         192 :     assert(cb);
     146             : 
     147         192 :     struct job *job = calloc(1, sizeof(*job));
     148         192 :     if (!job)
     149           0 :         lwan_status_critical_perror("calloc");
     150             : 
     151         192 :     job->cb = cb;
     152         192 :     job->data = data;
     153             : 
     154         192 :     if (LIKELY(!pthread_mutex_lock(&queue_mutex))) {
     155         192 :         list_add(&jobs, &job->jobs);
     156         192 :         pthread_mutex_unlock(&queue_mutex);
     157             :     } else {
     158           0 :         lwan_status_warning("Couldn't lock job mutex");
     159           0 :         free(job);
     160             :     }
     161         192 : }
     162             : 
     163           0 : void lwan_job_del(bool (*cb)(void *data), void *data)
     164             : {
     165             :     struct job *node, *next;
     166             : 
     167           0 :     assert(cb);
     168             : 
     169           0 :     if (LIKELY(!pthread_mutex_lock(&queue_mutex))) {
     170           0 :         list_for_each_safe(&jobs, node, next, jobs) {
     171           0 :             if (cb == node->cb && data == node->data) {
     172           0 :                 list_del(&node->jobs);
     173           0 :                 free(node);
     174             :             }
     175             :         }
     176           0 :         pthread_mutex_unlock(&queue_mutex);
     177             :     }
     178           0 : }

Generated by: LCOV version 1.15-2-gb9d6727