<commit_before>/************************************************************************************
  If not stated otherwise in this file or this component's LICENSE file the
  following copyright and licenses apply:

  Copyright 2021 RDK Management

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
**************************************************************************/

#include <sys/time.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include "scheduler.h"

struct timer_task {
    int id;                             /* identifier - used to delete */
    struct timeval timeout;             /* Next timeout */
    struct timeval interval;            /* Interval between execution */
    unsigned int repetitions;           /* number of configured repetitions */
    bool cancel;                        /* remove the task if true */

    bool execute;                       /* indication task should be executed */
    unsigned int execution_counter;     /* number of times the task was executed completely */

    int (*timer_call_back)(void *arg); /* Call back function */
    void *arg;                          /* Argument to be passed to call back function */
};

static int scheduler_calculate_timeout(struct scheduler *sched, struct timeval *t_now);
static int scheduler_get_number_tasks_pending(struct scheduler *sched, bool high_prio);
static int scheduler_remove_complete_tasks(struct scheduler *sched);

struct scheduler * scheduler_init(void)
{
    struct scheduler *sched = (struct scheduler *) malloc(sizeof(struct scheduler));

    if (sched != NULL) {
        pthread_mutex_init(&sched->lock, NULL);

        sched->high_priority_timer_list = queue_create();
        if (sched->high_priority_timer_list == NULL) {
            free(sched);
            pthread_mutex_destroy(&sched->lock);
            return NULL;
        }
        sched->num_hp_tasks = 0;
        sched->hp_index = 0;
        
        sched->timer_list = queue_create();
        if (sched->timer_list == NULL) {
            queue_destroy(sched->timer_list);
            free(sched);
            pthread_mutex_destroy(&sched->lock);
            return NULL;
        }
        sched->num_tasks = 0;
        sched->index = 0;
        sched->timer_list_age = 0;
    }
    return sched;
}

int scheduler_deinit(struct scheduler **sched)
{
    if (sched == NULL && *sched == NULL) {
        return -1;
    }
    pthread_mutex_lock(&(*sched)->lock);
    if ((*sched)->high_priority_timer_list != NULL) {
        queue_destroy((*sched)->high_priority_timer_list);
    }
    if ((*sched)->timer_list != NULL) {
        queue_destroy((*sched)->timer_list);
    }
    pthread_mutex_unlock(&(*sched)->lock);
    pthread_mutex_destroy(&(*sched)->lock); 
    free(*sched);
    *sched = NULL;
    pthread_mutex_destroy(&(*sched)->lock);
    return 0;
}

int scheduler_add_timer_task(struct scheduler *sched, bool high_prio, int *id,
                                int (*cb)(void *arg), void *arg, unsigned int interval_ms,
                                unsigned int repetitions)
{
    struct timer_task *tt;
    static int new_id = 0;

    if (sched == NULL || cb == NULL) {
        return -1;
    }
    pthread_mutex_lock(&sched->lock);
    tt = (struct timer_task *) malloc(sizeof(struct timer_task));
    if (tt == NULL)
    {
        pthread_mutex_unlock(&sched->lock);
        return -1;
    }
    new_id++;
    tt->id = new_id;
    timerclear(&(tt->timeout));
    tt->interval.tv_sec = (interval_ms / 1000);
    tt->interval.tv_usec = (interval_ms % 1000) * 1000;
    tt->repetitions = repetitions;
    tt->cancel = false;
    tt->execute = false;
    tt->execution_counter = 0;
    tt->timer_call_back = cb;
    tt->arg = arg;

    if (high_prio == true) {
        queue_push(sched->high_priority_timer_list, tt);
        sched->num_hp_tasks++;
    } else {
        queue_push(sched->timer_list, tt);
        sched->num_tasks++;
    }
    if (id != NULL) {
        *id = tt->id;
    }
    pthread_mutex_unlock(&sched->lock);
    return 0;
}

int scheduler_cancel_timer_task(struct scheduler *sched, int id)
{
    struct timer_task *tt;
    unsigned int i;

    if (sched == NULL) {
        return -1;
    }
    pthread_mutex_lock(&sched->lock);
    for (i = 0; i < sched->num_hp_tasks; i++) {
        tt = queue_peek(sched->high_priority_timer_list, i);
        if (tt != NULL && tt->id == id) {
            tt->cancel = true;
            pthread_mutex_unlock(&sched->lock);
            return 0;
        }
    }
    for (i = 0; i < sched->num_tasks; i++) {
        tt = queue_peek(sched->timer_list, i);
        if (tt != NULL && tt->id == id) {
            tt->cancel = true;
            pthread_mutex_unlock(&sched->lock);
            return 0;
        }
    }
    pthread_mutex_unlock(&sched->lock);
    /* could not find the task */
    return -1;
}

int scheduler_update_timer_task_interval(struct scheduler *sched, int id, unsigned int interval_ms)
{
    struct timer_task *tt;
    unsigned int i;

    if (sched == NULL) {
        return -1;
    }
    pthread_mutex_lock(&sched->lock);
    for (i = 0; i < sched->num_hp_tasks; i++) {
        tt = queue_peek(sched->high_priority_timer_list, i);
        if (tt != NULL && tt->id == id) {
            tt->interval.tv_sec = (interval_ms / 1000);
            tt->interval.tv_usec = (interval_ms % 1000) * 1000;
            pthread_mutex_unlock(&sched->lock);
            return 0;
        }
    }
    for (i = 0; i < sched->num_tasks; i++) {
        tt = queue_peek(sched->timer_list, i);
        if (tt != NULL && tt->id == id) {
            tt->interval.tv_sec = (interval_ms / 1000);
            tt->interval.tv_usec = (interval_ms % 1000) * 1000;
            pthread_mutex_unlock(&sched->lock);
            return 0;<commit_msg>RDKB-39626 Fix telemetry log interval<commit_after>/************************************************************************************
  If not stated otherwise in this file or this component's LICENSE file the
  following copyright and licenses apply:

  Copyright 2021 RDK Management

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
**************************************************************************/

#include <sys/time.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include "scheduler.h"

struct timer_task {
    int id;                             /* identifier - used to delete */
    struct timeval timeout;             /* Next timeout */
    struct timeval interval;            /* Interval between execution */
    unsigned int repetitions;           /* number of configured repetitions */
    bool cancel;                        /* remove the task if true */

    bool execute;                       /* indication task should be executed */
    unsigned int execution_counter;     /* number of times the task was executed completely */

    int (*timer_call_back)(void *arg); /* Call back function */
    void *arg;                          /* Argument to be passed to call back function */
};

static int scheduler_calculate_timeout(struct scheduler *sched, struct timeval *t_now);
static int scheduler_get_number_tasks_pending(struct scheduler *sched, bool high_prio);
static int scheduler_remove_complete_tasks(struct scheduler *sched);

struct scheduler * scheduler_init(void)
{
    struct scheduler *sched = (struct scheduler *) malloc(sizeof(struct scheduler));

    if (sched != NULL) {
        pthread_mutex_init(&sched->lock, NULL);

        sched->high_priority_timer_list = queue_create();
        if (sched->high_priority_timer_list == NULL) {
            free(sched);
            pthread_mutex_destroy(&sched->lock);
            return NULL;
        }
        sched->num_hp_tasks = 0;
        sched->hp_index = 0;
        
        sched->timer_list = queue_create();
        if (sched->timer_list == NULL) {
            queue_destroy(sched->timer_list);
            free(sched);
            pthread_mutex_destroy(&sched->lock);
            return NULL;
        }
        sched->num_tasks = 0;
        sched->index = 0;
        sched->timer_list_age = 0;
    }
    return sched;
}

int scheduler_deinit(struct scheduler **sched)
{
    if (sched == NULL && *sched == NULL) {
        return -1;
    }
    pthread_mutex_lock(&(*sched)->lock);
    if ((*sched)->high_priority_timer_list != NULL) {
        queue_destroy((*sched)->high_priority_timer_list);
    }
    if ((*sched)->timer_list != NULL) {
        queue_destroy((*sched)->timer_list);
    }
    pthread_mutex_unlock(&(*sched)->lock);
    pthread_mutex_destroy(&(*sched)->lock); 
    free(*sched);
    *sched = NULL;
    pthread_mutex_destroy(&(*sched)->lock);
    return 0;
}

int scheduler_add_timer_task(struct scheduler *sched, bool high_prio, int *id,
                                int (*cb)(void *arg), void *arg, unsigned int interval_ms,
                                unsigned int repetitions)
{
    struct timer_task *tt;
    static int new_id = 0;

    if (sched == NULL || cb == NULL) {
        return -1;
    }
    pthread_mutex_lock(&sched->lock);
    tt = (struct timer_task *) malloc(sizeof(struct timer_task));
    if (tt == NULL)
    {
        pthread_mutex_unlock(&sched->lock);
        return -1;
    }
    new_id++;
    tt->id = new_id;
    timerclear(&(tt->timeout));
    tt->interval.tv_sec = (interval_ms / 1000);
    tt->interval.tv_usec = (interval_ms % 1000) * 1000;
    tt->repetitions = repetitions;
    tt->cancel = false;
    tt->execute = false;
    tt->execution_counter = 0;
    tt->timer_call_back = cb;
    tt->arg = arg;

    if (high_prio == true) {
        queue_push(sched->high_priority_timer_list, tt);
        sched->num_hp_tasks++;
    } else {
        queue_push(sched->timer_list, tt);
        sched->num_tasks++;
    }
    if (id != NULL) {
        *id = tt->id;
    }
    pthread_mutex_unlock(&sched->lock);
    return 0;
}

int scheduler_cancel_timer_task(struct scheduler *sched, int id)
{
    struct timer_task *tt;
    unsigned int i;

    if (sched == NULL) {
        return -1;
    }
    pthread_mutex_lock(&sched->lock);
    for (i = 0; i < sched->num_hp_tasks; i++) {
        tt = queue_peek(sched->high_priority_timer_list, i);
        if (tt != NULL && tt->id == id) {
            tt->cancel = true;
            pthread_mutex_unlock(&sched->lock);
            return 0;
        }
    }
    for (i = 0; i < sched->num_tasks; i++) {
        tt = queue_peek(sched->timer_list, i);
        if (tt != NULL && tt->id == id) {
            tt->cancel = true;
            pthread_mutex_unlock(&sched->lock);
            return 0;
        }
    }
    pthread_mutex_unlock(&sched->lock);
    /* could not find the task */
    return -1;
}

int scheduler_update_timer_task_interval(struct scheduler *sched, int id, unsigned int interval_ms)
{
    struct timer_task *tt;
    unsigned int i;
    struct timeval new_timer, res;

    if (sched == NULL) {
        return -1;
    }
    pthread_mutex_lock(&sched->lock);
    for (i = 0; i < sched->num_hp_tasks; i++) {
        tt = queue_peek(sched->high_priority_timer_list, i);
        if (tt != NULL && tt->id == id) {
            new_timer.tv_sec = (interval_ms / 1000);
            new_timer.tv_usec = (interval_ms % 1000) * 1000;
            if(timercmp(&new_timer, &(tt->interval), >)) {
                timersub(&new_timer, &(tt->interval), &res);
                timeradd(&(tt->timeout), &res, &(tt->timeout));
                tt->interval.tv_sec = (interval_ms / 1000);
                tt->interval.tv_usec = (interval_ms % 1000) * 1000;
            } else if (timercmp(&new_timer, &(tt->interval), <)) {
                timersub(&(tt->interval), &new_timer, &res);
                timersub(&(tt->timeout), &res, &(tt->timeout));
                tt->interval.tv_sec = (interval_ms / 1000);
                tt->interval.tv_usec = (interval_ms % 1000) * 1000;
            }
            pthread_mutex_unlock(&sched->lock);
            return 0;
        }
    }
    for (i = 0; i < sched->num_tasks; i++) {
        tt = queue_peek(sched->timer_list, i);
        if (tt != NULL && tt->id == id) {
            new_timer.tv_sec = (interval_ms / 1000);
            new_timer.tv_usec = (interval_ms % 1000) * 1000;
            if(timercmp(&new_timer, &(tt->interval), >)) {
                timersub(&new_timer, &(tt->interval), &res);
                timeradd(&(tt->timeout), &res, &(tt->timeout));
                tt->interval.tv_sec = (interval_ms / 1000);
                tt->interval.tv_usec = (interval_ms % 1000) * 1000;
            } else if (timercmp(&new_timer, &(tt->interval), <)) {
                timersub(&(tt->interval), &new_timer, &res);
                timersub(&(tt->timeout), &res, &(tt->timeout));
                tt->interval.tv_sec = (interval_ms / 1000);
                tt->interval.tv_usec = (interval_ms % 1000) * 1000;
            }
            pthread_mutex_unlock(&sched->lock);
            return 0;
{'fraction_non_alphanumeric': 0.14687522422329052, 'fraction_numerical': 0.013417521704814523, 'mean_word_length': 2.3424460431654675, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 163, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '507781', 'n_tokens_mistral': 4341, 'n_tokens_neox': 4103, 'n_words': 1057}