• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mendersoftware / mender-mcu / 1652801795

03 Feb 2025 08:48AM UTC coverage: 25.939% (+0.3%) from 25.682%
1652801795

push

gitlab-ci

danielskinstad
chore: explicit error for no files in zephyr-image-update-module

Check if the aritfact has a payload file by adding a boolean that's set
when the download artifact flash callback is called.

Ticket: MEN-7804

Signed-off-by: Daniel Skinstad Drabitzius <daniel.drabitzius@northern.tech>

739 of 2849 relevant lines covered (25.94%)

8.56 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/platform/scheduler/posix/src/mender-scheduler.c
1
/**
2
 * @file      mender-scheduler.c
3
 * @brief     Mender scheduler interface for Posix platform
4
 *
5
 * Copyright joelguittet and mender-mcu-client contributors
6
 *
7
 * Licensed under the Apache License, Version 2.0 (the "License");
8
 * you may not use this file except in compliance with the License.
9
 * You may obtain a copy of the License at
10
 *
11
 *     http://www.apache.org/licenses/LICENSE-2.0
12
 *
13
 * Unless required by applicable law or agreed to in writing, software
14
 * distributed under the License is distributed on an "AS IS" BASIS,
15
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 * See the License for the specific language governing permissions and
17
 * limitations under the License.
18
 */
19

20
#include <errno.h>
21
#include <math.h>
22
#include <mqueue.h>
23
#include <pthread.h>
24
#include <signal.h>
25
#include <sys/reboot.h>
26
#include <time.h>
27
#include <unistd.h>
28

29
#include "mender-alloc.h"
30
#include "mender-log.h"
31
#include "mender-scheduler.h"
32
#include "mender-utils.h"
33

34
/**
35
 * @brief Default work queue stack size (kB)
36
 */
37
#ifndef CONFIG_MENDER_SCHEDULER_WORK_QUEUE_STACK_SIZE
38
#define CONFIG_MENDER_SCHEDULER_WORK_QUEUE_STACK_SIZE (64)
39
#endif /* CONFIG_MENDER_SCHEDULER_WORK_QUEUE_STACK_SIZE */
40

41
/**
42
 * @brief Default work queue priority
43
 */
44
#ifndef CONFIG_MENDER_SCHEDULER_WORK_QUEUE_PRIORITY
45
#define CONFIG_MENDER_SCHEDULER_WORK_QUEUE_PRIORITY (0)
46
#endif /* CONFIG_MENDER_SCHEDULER_WORK_QUEUE_PRIORITY */
47

48
/**
49
 * @brief Default work queue length
50
 */
51
#ifndef CONFIG_MENDER_SCHEDULER_WORK_QUEUE_LENGTH
52
#define CONFIG_MENDER_SCHEDULER_WORK_QUEUE_LENGTH (10)
53
#endif /* CONFIG_MENDER_SCHEDULER_WORK_QUEUE_LENGTH */
54

55
/**
56
 * @brief Work context
57
 */
58
typedef struct mender_platform_work_t {
59
    mender_scheduler_work_params_t params;       /**< Work parameters */
60
    pthread_mutex_t                sem_handle;   /**< Semaphore used to indicate work is pending or executing */
61
    timer_t                        timer_handle; /**< Timer used to periodically execute work */
62
    bool                           activated;    /**< Flag indicating the work is activated */
63
} mender_platform_work_t;
64

65
/**
66
 *
67
 * @brief Work queue parameters
68
 */
69
#define MENDER_SCHEDULER_WORK_QUEUE_NAME  "/mender-work-queue"
70
#define MENDER_SCHEDULER_WORK_QUEUE_PERMS (0644)
71

72
/**
73
 * @brief Function used to handle work context timer when it expires
74
 * @param timer_data Timer data
75
 */
76
static void mender_scheduler_timer_callback(union sigval timer_data);
77

78
/**
79
 * @brief Thread used to handle work queue
80
 * @param arg Not used
81
 * @return Not used
82
 */
83
static void *mender_scheduler_work_queue_thread(void *arg);
84

85
/**
86
 * @brief Work queue handle
87
 */
88
static mqd_t mender_scheduler_work_queue_handle;
89

90
/**
91
 * @brief Work queue thread handle
92
 */
93
static pthread_t mender_scheduler_work_queue_thread_handle;
94

95
mender_err_t
96
mender_scheduler_init(void) {
×
97
    int ret;
98

99
    /* Create and start work queue */
100
    struct mq_attr mq_attr = { 0 };
×
101
    mq_attr.mq_maxmsg      = CONFIG_MENDER_SCHEDULER_WORK_QUEUE_LENGTH;
×
102
    mq_attr.mq_msgsize     = sizeof(mender_platform_work_t *);
×
103
    mq_unlink(MENDER_SCHEDULER_WORK_QUEUE_NAME);
×
104
    if ((mender_scheduler_work_queue_handle = mq_open(MENDER_SCHEDULER_WORK_QUEUE_NAME, O_CREAT | O_RDWR, MENDER_SCHEDULER_WORK_QUEUE_PERMS, &mq_attr)) < 0) {
×
105
        mender_log_error("Unable to create work queue (errno=%d)", errno);
×
106
        return MENDER_FAIL;
×
107
    }
108
    pthread_attr_t pthread_attr;
109
    if (0 != (ret = pthread_attr_init(&pthread_attr))) {
×
110
        mender_log_error("Unable to initialize work queue thread attributes (ret=%d)", ret);
×
111
        return MENDER_FAIL;
×
112
    }
113
    if (0
×
114
        != (ret = pthread_attr_setstacksize(
×
115
                &pthread_attr, ((CONFIG_MENDER_SCHEDULER_WORK_QUEUE_STACK_SIZE > 16) ? CONFIG_MENDER_SCHEDULER_WORK_QUEUE_STACK_SIZE : 16) * 1024))) {
116
        mender_log_error("Unable to set work queue thread stack size (ret=%d)", ret);
×
117
        return MENDER_FAIL;
×
118
    }
119
    if (0 != (ret = pthread_create(&mender_scheduler_work_queue_thread_handle, &pthread_attr, mender_scheduler_work_queue_thread, NULL))) {
×
120
        mender_log_error("Unable to create work queue thread (ret=%d)", ret);
×
121
        return MENDER_FAIL;
×
122
    }
123
    if (0 != (ret = pthread_setschedprio(mender_scheduler_work_queue_thread_handle, CONFIG_MENDER_SCHEDULER_WORK_QUEUE_PRIORITY))) {
×
124
        mender_log_error("Unable to set work queue thread priority (ret=%d)", ret);
×
125
        return MENDER_FAIL;
×
126
    }
127

128
    return MENDER_OK;
×
129
}
130

131
mender_err_t
132
mender_scheduler_work_create(mender_scheduler_work_params_t *work_params, mender_work_t **work) {
×
133
    assert(NULL != work_params);
×
134
    assert(NULL != work_params->function);
×
135
    assert(NULL != work_params->name);
×
136
    assert(NULL != work);
×
137

138
    /* Create work context */
139
    mender_platform_work_t *work_context = mender_calloc(1, sizeof(mender_platform_work_t));
×
140
    if (NULL == work_context) {
×
141
        mender_log_error("Unable to allocate memory");
×
142
        goto FAIL;
×
143
    }
144

145
    /* Copy work parameters */
146
    work_context->params.function = work_params->function;
×
147
    work_context->params.period   = work_params->period;
×
148
    if (NULL == (work_context->params.name = mender_utils_strdup(work_params->name))) {
×
149
        mender_log_error("Unable to allocate memory");
×
150
        goto FAIL;
×
151
    }
152

153
    /* Create semaphore used to protect work function */
154
    if (0 != pthread_mutex_init(&work_context->sem_handle, NULL)) {
×
155
        mender_log_error("Unable to create semaphore");
×
156
        goto FAIL;
×
157
    }
158

159
    /* Create timer to handle the work periodically */
160
    struct sigevent sev       = { 0 };
×
161
    sev.sigev_notify          = SIGEV_THREAD;
×
162
    sev.sigev_notify_function = mender_scheduler_timer_callback;
×
163
    sev.sigev_value.sival_ptr = work_context;
×
164
    if (0 != timer_create(CLOCK_REALTIME, &sev, &work_context->timer_handle)) {
×
165
        mender_log_error("Unable to create timer");
×
166
        goto FAIL;
×
167
    }
168

169
    /* Return handle to the new work */
170
    *work = work_context;
×
171

172
    return MENDER_OK;
×
173

174
FAIL:
×
175

176
    /* Release memory */
177
    if (NULL != work_context) {
×
178
        timer_delete(work_context->timer_handle);
×
179
        pthread_mutex_destroy(&work_context->sem_handle);
×
180
        mender_free(work_context->params.name);
×
181
        mender_free(work_context);
×
182
    }
183

184
    return MENDER_FAIL;
×
185
}
186

187
mender_err_t
188
mender_scheduler_work_activate(mender_work_t *work) {
×
189
    assert(NULL != work);
×
190

191
    /* Give semaphore used to protect the work function */
192
    if (0 != pthread_mutex_unlock(&work->sem_handle)) {
×
193
        mender_log_error("Unable to give semaphore");
×
194
        return MENDER_FAIL;
×
195
    }
196

197
    /* Check the timer period */
198
    if (work->params.period > 0) {
×
199

200
        /* Start the timer to handle the work */
201
        struct itimerspec its  = { 0 };
×
202
        its.it_value.tv_sec    = work->params.period;
×
203
        its.it_interval.tv_sec = work->params.period;
×
204
        if (0 != timer_settime(work->timer_handle, 0, &its, NULL)) {
×
205
            mender_log_error("Unable to start timer");
×
206
            return MENDER_FAIL;
×
207
        }
208

209
        /* Execute the work now */
210
        union sigval timer_data;
211
        timer_data.sival_ptr = (void *)work;
×
212
        mender_scheduler_timer_callback(timer_data);
×
213
    }
214

215
    /* Indicate the work has been activated */
216
    work->activated = true;
×
217

218
    return MENDER_OK;
×
219
}
220

221
mender_err_t
222
mender_scheduler_work_set_period(mender_work_t *work, uint32_t period) {
×
223
    assert(NULL != work);
×
224

225
    /* Set timer period */
226
    work->params.period   = period;
×
227
    struct itimerspec its = { 0 };
×
228
    if (work->params.period > 0) {
×
229
        its.it_value.tv_sec    = work->params.period;
×
230
        its.it_interval.tv_sec = work->params.period;
×
231
    }
232
    if (0 != timer_settime(work->timer_handle, 0, &its, NULL)) {
×
233
        mender_log_error("Unable to set timer period");
×
234
        return MENDER_FAIL;
×
235
    }
236

237
    return MENDER_OK;
×
238
}
239

240
mender_err_t
241
mender_scheduler_work_execute(mender_work_t *work) {
×
242
    assert(NULL != work);
×
243

244
    /* Execute the work now */
245
    union sigval timer_data;
246
    timer_data.sival_ptr = (void *)work;
×
247
    mender_scheduler_timer_callback(timer_data);
×
248

249
    return MENDER_OK;
×
250
}
251

252
mender_err_t
253
mender_scheduler_work_deactivate(mender_work_t *work) {
×
254
    assert(NULL != work);
×
255

256
    /* Check if the work was activated */
257
    if (work->activated) {
×
258

259
        /* Stop the timer used to periodically execute the work (if it is running) */
260
        struct itimerspec its = { 0 };
×
261
        if (0 != timer_settime(work->timer_handle, 0, &its, NULL)) {
×
262
            mender_log_error("Unable to stop timer");
×
263
            return MENDER_FAIL;
×
264
        }
265

266
        /* Wait if the work is pending or executing */
267
        if (0 != pthread_mutex_lock(&work->sem_handle)) {
×
268
            mender_log_error("Work '%s' is pending or executing", work->params.name);
×
269
            return MENDER_FAIL;
×
270
        }
271

272
        /* Indicate the work has been deactivated */
273
        work->activated = false;
×
274
    }
275

276
    return MENDER_OK;
×
277
}
278

279
mender_err_t
280
mender_scheduler_work_delete(mender_work_t *work) {
×
281
    if (NULL == work) {
×
282
        return MENDER_OK;
×
283
    }
284

285
    timer_delete(work->timer_handle);
×
286
    pthread_mutex_destroy(&work->sem_handle);
×
287
    mender_free(work->params.name);
×
288
    mender_free(work);
×
289

290
    return MENDER_OK;
×
291
}
292
mender_err_t
293
mender_scheduler_exit(void) {
×
294
    /* Submit empty work to the work queue, this ask the work queue thread to terminate */
295
    mender_platform_work_t *work = NULL;
×
296
    if (0 != mq_send(mender_scheduler_work_queue_handle, (const char *)&work, sizeof(mender_platform_work_t *), 0)) {
×
297
        mender_log_error("Unable to submit empty work to the work queue");
×
298
        return MENDER_FAIL;
×
299
    }
300

301
    /* Wait end of execution of the work queue thread */
302
    pthread_join(mender_scheduler_work_queue_thread_handle, NULL);
×
303

304
    return MENDER_OK;
×
305
}
306

307
static void
308
mender_scheduler_timer_callback(union sigval timer_data) {
×
309
    /* Get work context */
310
    mender_platform_work_t *work = (mender_platform_work_t *)timer_data.sival_ptr;
×
311
    assert(NULL != work);
×
312

313
    /* Exit if the work is already pending or executing */
314
    struct timespec timeout = { 0 };
×
315
    if (0 != pthread_mutex_timedlock(&work->sem_handle, &timeout)) {
×
316
        mender_log_debug("Work '%s' is not activated, already pending or executing", work->params.name);
317
        return;
×
318
    }
319

320
    /* Submit the work to the work queue */
321
    if (0 != mq_send(mender_scheduler_work_queue_handle, (const char *)&work, sizeof(mender_platform_work_t *), 0)) {
×
322
        mender_log_warning("Unable to submit work '%s' to the work queue", work->params.name);
×
323
        pthread_mutex_unlock(&work->sem_handle);
×
324
    }
325
}
326

327
__attribute__((noreturn)) static void *
328
mender_scheduler_work_queue_thread(MENDER_ARG_UNUSED void *arg) {
×
329
    mender_platform_work_t *work = NULL;
×
330

331
    /* Handle work to be executed */
332
    while (mq_receive(mender_scheduler_work_queue_handle, (char *)&work, sizeof(mender_platform_work_t *), NULL) > 0) {
×
333

334
        /* Check if empty work is received from the work queue, this ask the work queue thread to terminate */
335
        if (NULL == work) {
×
336
            goto END;
×
337
        }
338

339
        /* Call work function */
340
        if (MENDER_DONE == work->params.function()) {
×
341

342
            /* Work is done, stop timer used to execute the work periodically */
343
            struct itimerspec its = { 0 };
×
344
            if (0 != timer_settime(work->timer_handle, 0, &its, NULL)) {
×
345
                mender_log_error("Unable to stop timer");
×
346
            }
347
        }
348

349
        /* Release semaphore used to protect the work function */
350
        pthread_mutex_unlock(&work->sem_handle);
×
351
    }
352

353
END:
×
354
    /* Release memory */
355
    mq_close(mender_scheduler_work_queue_handle);
×
356
    mq_unlink(MENDER_SCHEDULER_WORK_QUEUE_NAME);
×
357

358
    /* Terminate work queue thread */
359
    pthread_exit(NULL);
×
360
}
361

362
mender_err_t
363
mender_scheduler_mutex_create(void **handle) {
×
364

365
    assert(NULL != handle);
×
366

367
    /* Create mutex */
368
    if (NULL == (*handle = mender_malloc(sizeof(pthread_mutex_t)))) {
×
369
        return MENDER_FAIL;
×
370
    }
371
    if (0 != pthread_mutex_init(*handle, NULL)) {
×
372
        FREE_AND_NULL(*handle);
×
373
        return MENDER_FAIL;
×
374
    }
375

376
    return MENDER_OK;
×
377
}
378

379
mender_err_t
380
mender_scheduler_mutex_take(void *handle, int32_t delay_ms) {
×
381

382
    assert(NULL != handle);
×
383

384
    /* Take mutex */
385
    if (delay_ms >= 0) {
×
386
        struct timespec timeout;
387
        timeout.tv_sec  = delay_ms / 1000;
×
388
        timeout.tv_nsec = (delay_ms % 1000) * 1000000;
×
389
        if (0 != pthread_mutex_timedlock((pthread_mutex_t *)handle, &timeout)) {
×
390
            return MENDER_FAIL;
×
391
        }
392
    } else {
393
        if (0 != pthread_mutex_lock((pthread_mutex_t *)handle)) {
×
394
            return MENDER_FAIL;
×
395
        }
396
    }
397

398
    return MENDER_OK;
×
399
}
400

401
mender_err_t
402
mender_scheduler_mutex_give(void *handle) {
×
403

404
    assert(NULL != handle);
×
405

406
    /* Give mutex */
407
    if (0 != pthread_mutex_unlock((pthread_mutex_t *)handle)) {
×
408
        return MENDER_FAIL;
×
409
    }
410

411
    return MENDER_OK;
×
412
}
413

414
mender_err_t
415
mender_scheduler_mutex_delete(void *handle) {
×
416

417
    assert(NULL != handle);
×
418

419
    /* Release memory */
420
    pthread_mutex_destroy((pthread_mutex_t *)handle);
×
421
    mender_free(handle);
×
422

423
    return MENDER_OK;
×
424
}
425

426
void
427
mender_scheduler_reboot(void) {
×
428
    reboot(RB_AUTOBOOT);
×
429
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc