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

pybricks / pybricks-micropython / 19016791193

02 Nov 2025 06:40PM UTC coverage: 57.167% (-2.6%) from 59.744%
19016791193

Pull #406

github

laurensvalk
bricks/virtualhub: Replace with embedded simulation.

Instead of using the newly introduced simhub alongside the virtualhub, we'll just replace the old one entirely now that it has reached feature parity. We can keep calling it the virtualhub.
Pull Request #406: New virtual hub for more effective debugging

41 of 48 new or added lines in 7 files covered. (85.42%)

414 existing lines in 53 files now uncovered.

4479 of 7835 relevant lines covered (57.17%)

17178392.75 hits per line

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

68.57
/lib/contiki-core/sys/process.c
1
// SPDX-License-Identifier: BSD-3-Clause
2
/*
3
 * Copyright (c) 2005, Swedish Institute of Computer Science
4
 * All rights reserved.
5
 *
6
 * Redistribution and use in source and binary forms, with or without
7
 * modification, are permitted provided that the following conditions
8
 * are met:
9
 * 1. Redistributions of source code must retain the above copyright
10
 *    notice, this list of conditions and the following disclaimer.
11
 * 2. Redistributions in binary form must reproduce the above copyright
12
 *    notice, this list of conditions and the following disclaimer in the
13
 *    documentation and/or other materials provided with the distribution.
14
 * 3. Neither the name of the Institute nor the names of its contributors
15
 *    may be used to endorse or promote products derived from this software
16
 *    without specific prior written permission.
17
 *
18
 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
19
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
22
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28
 * SUCH DAMAGE.
29
 *
30
 * This file is part of the Contiki operating system.
31
 *
32
 */
33

34
/**
35
 * \addtogroup process
36
 * @{
37
 */
38

39
/**
40
 * \file
41
 *         Implementation of the Contiki process kernel.
42
 * \author
43
 *         Adam Dunkels <adam@sics.se>
44
 *
45
 */
46

47
#include <stdio.h>
48

49
#include "sys/process.h"
50
#include "sys/arg.h"
51

52
/*
53
 * Pointer to the currently running process structure.
54
 */
55
struct process *process_list = NULL;
56
struct process *process_current = NULL;
57

58
static process_event_t lastevent;
59

60
/*
61
 * Structure used for keeping the queue of active events.
62
 */
63
struct event_data {
64
    process_event_t ev;
65
    process_data_t data;
66
    struct process *p;
67
};
68

69
static process_num_events_t nevents, fevent;
70
static struct event_data events[PROCESS_CONF_NUMEVENTS];
71

72
#if PROCESS_CONF_STATS
73
process_num_events_t process_maxevents;
74
#endif
75

76
static volatile unsigned char poll_requested;
77

78
#define PROCESS_STATE_NONE        0
79
#define PROCESS_STATE_RUNNING     1
80
#define PROCESS_STATE_CALLED      2
81

82
static void call_process(struct process *p, process_event_t ev, process_data_t data);
83

84
#define DEBUG 0
85
#if DEBUG
86
#include <stdio.h>
87
#define PRINTF(...) printf(__VA_ARGS__)
88
#else
89
#define PRINTF(...)
90
#endif
91

92
/*---------------------------------------------------------------------------*/
93
process_event_t
94
process_alloc_event(void) {
×
95
    return lastevent++;
×
96
}
97
/*---------------------------------------------------------------------------*/
98
void
99
process_start(struct process *p) {
52✔
100
    struct process *q;
101

102
    /* First make sure that we don't try to start a process that is
103
       already running. */
104
    for (q = process_list; q != p && q != NULL; q = q->next) {;
78✔
105
    }
106

107
    /* If we found the process on the process list, we bail out. */
108
    if (q == p) {
52✔
UNCOV
109
        return;
×
110
    }
111
    /* Put on the procs list.*/
112
    p->next = process_list;
52✔
113
    process_list = p;
52✔
114
    p->state = PROCESS_STATE_RUNNING;
52✔
115
    PT_INIT(&p->pt);
52✔
116

117
    PRINTF("process: starting '%s'\n", PROCESS_NAME_STRING(p));
118

119
    /* Post a synchronous initialization event to the process. */
120
    process_post_synch(p, PROCESS_EVENT_INIT, NULL);
52✔
121
}
122
/*---------------------------------------------------------------------------*/
123
static void
124
exit_process(struct process *p, struct process *fromprocess) {
×
125
    register struct process *q;
126
    struct process *old_current = process_current;
×
127

128
    PRINTF("process: exit_process '%s'\n", PROCESS_NAME_STRING(p));
129

130
    /* Make sure the process is in the process list before we try to
131
       exit it. */
132
    for (q = process_list; q != p && q != NULL; q = q->next) {;
×
133
    }
134
    if (q == NULL) {
×
UNCOV
135
        return;
×
136
    }
137

138
    if (process_is_running(p)) {
×
139
        /* Process was running */
140
        p->state = PROCESS_STATE_NONE;
×
141

142
        /*
143
         * Post a synchronous event to all processes to inform them that
144
         * this process is about to exit. This will allow services to
145
         * deallocate state associated with this process.
146
         */
147
        for (q = process_list; q != NULL; q = q->next) {
×
148
            if (p != q) {
×
149
                call_process(q, PROCESS_EVENT_EXITED, (process_data_t)p);
×
150
            }
151
        }
152

153
        if (p->thread != NULL && p != fromprocess) {
×
154
            /* Post the exit event to the process that is about to exit. */
155
            process_current = p;
×
156
            p->thread(&p->pt, PROCESS_EVENT_EXIT, NULL);
×
157
        }
158
    }
159

160
    if (p == process_list) {
×
161
        process_list = process_list->next;
×
162
    } else {
163
        for (q = process_list; q != NULL; q = q->next) {
×
164
            if (q->next == p) {
×
165
                q->next = p->next;
×
166
                break;
×
167
            }
168
        }
169
    }
170

171
    process_current = old_current;
×
172
}
173
/*---------------------------------------------------------------------------*/
174
static void
175
call_process(struct process *p, process_event_t ev, process_data_t data) {
300,810✔
176
    int ret;
177

178
    #if DEBUG
179
    if (p->state == PROCESS_STATE_CALLED) {
180
        printf("process: process '%s' called again with event 0x%02X\n", PROCESS_NAME_STRING(p), ev);
181
    }
182
    #endif /* DEBUG */
183

184
    if ((p->state & PROCESS_STATE_RUNNING) &&
300,810✔
185
        p->thread != NULL) {
300,810✔
186
        PRINTF("process: calling process '%s' with event 0x%02X\n", PROCESS_NAME_STRING(p), ev);
187
        process_current = p;
300,810✔
188
        p->state = PROCESS_STATE_CALLED;
300,810✔
189
        ret = p->thread(&p->pt, ev, data);
300,810✔
190
        if (ret == PT_EXITED ||
300,810✔
191
            ret == PT_ENDED ||
300,810✔
192
            ev == PROCESS_EVENT_EXIT) {
193
            exit_process(p, p);
×
194
        } else {
195
            p->state = PROCESS_STATE_RUNNING;
300,810✔
196
        }
197
    }
198
}
300,810✔
199
/*---------------------------------------------------------------------------*/
200
void
201
process_exit(struct process *p) {
×
202
    exit_process(p, PROCESS_CURRENT());
×
203
}
×
204
/*---------------------------------------------------------------------------*/
205
void
206
process_init(void) {
26✔
207
    lastevent = PROCESS_EVENT_MAX;
26✔
208

209
    nevents = fevent = 0;
26✔
210
    #if PROCESS_CONF_STATS
211
    process_maxevents = 0;
212
    #endif /* PROCESS_CONF_STATS */
213

214
    process_current = process_list = NULL;
26✔
215
}
26✔
216
/*---------------------------------------------------------------------------*/
217
/*
218
 * Call each process' poll handler.
219
 */
220
/*---------------------------------------------------------------------------*/
221
static void
222
do_poll(void) {
200,358✔
223
    struct process *p;
224

225
    poll_requested = 0;
200,358✔
226
    /* Call the processes that needs to be polled. */
227
    for (p = process_list; p != NULL; p = p->next) {
601,074✔
228
        if (p->needspoll) {
400,716✔
229
            p->state = PROCESS_STATE_RUNNING;
200,358✔
230
            p->needspoll = 0;
200,358✔
231
            call_process(p, PROCESS_EVENT_POLL, NULL);
200,358✔
232
        }
233
    }
234
}
200,358✔
235
/*---------------------------------------------------------------------------*/
236
/*
237
 * Process the next event in the event queue and deliver it to
238
 * listening processes.
239
 */
240
/*---------------------------------------------------------------------------*/
241
static void
242
do_event(void) {
526,525✔
243
    process_event_t ev;
244
    process_data_t data;
245
    struct process *receiver;
246
    struct process *p;
247

248
    /*
249
     * If there are any events in the queue, take the first one and walk
250
     * through the list of processes to see if the event should be
251
     * delivered to any of them. If so, we call the event handler
252
     * function for the process. We only process one event at a time and
253
     * call the poll handlers inbetween.
254
     */
255

256
    if (nevents > 0) {
526,525✔
257

258
        /* There are events that we should deliver. */
259
        ev = events[fevent].ev;
100,316✔
260

261
        data = events[fevent].data;
100,316✔
262
        receiver = events[fevent].p;
100,316✔
263

264
        /* Since we have seen the new event, we move pointer upwards
265
           and decrease the number of events. */
266
        fevent = (fevent + 1) % PROCESS_CONF_NUMEVENTS;
100,316✔
267
        --nevents;
100,316✔
268

269
        /* If this is a broadcast event, we deliver it to all events, in
270
           order of their priority. */
271
        if (receiver == PROCESS_BROADCAST) {
100,316✔
272
            for (p = process_list; p != NULL; p = p->next) {
252✔
273

274
                /* If we have been requested to poll a process, we do this in
275
                   between processing the broadcast event. */
276
                if (poll_requested) {
168✔
277
                    do_poll();
×
278
                }
279
                call_process(p, ev, data);
168✔
280
            }
281
        } else {
282
            /* This is not a broadcast event, so we deliver it to the
283
               specified process. */
284
            /* If the event was an INIT event, we should also update the
285
               state of the process. */
286
            if (ev == PROCESS_EVENT_INIT) {
100,232✔
287
                receiver->state = PROCESS_STATE_RUNNING;
×
288
            }
289

290
            /* Make sure that the process actually is running. */
291
            call_process(receiver, ev, data);
100,232✔
292
        }
293
    }
294
}
526,525✔
295
/*---------------------------------------------------------------------------*/
296
int
297
process_run(void) {
526,525✔
298
    /* Process poll events. */
299
    if (poll_requested) {
526,525✔
300
        do_poll();
200,358✔
301
    }
302

303
    /* Process one event from the queue */
304
    do_event();
526,525✔
305

306
    return nevents + poll_requested;
526,525✔
307
}
308
/*---------------------------------------------------------------------------*/
309
int
310
process_nevents(void) {
82,748✔
311
    return nevents + poll_requested;
82,748✔
312
}
313
/*---------------------------------------------------------------------------*/
314
int
315
process_post(struct process *p, process_event_t ev, process_data_t data) {
100,316✔
316
    process_num_events_t snum;
317

318
    if (PROCESS_CURRENT() == NULL) {
100,316✔
319
        PRINTF("process_post: NULL process posts event 0x%02X to process '%s', nevents %d\n",
320
            ev, PROCESS_NAME_STRING(p), nevents);
321
    } else {
322
        PRINTF("process_post: Process '%s' posts event 0x%02X to process '%s', nevents %d\n",
323
            PROCESS_NAME_STRING(PROCESS_CURRENT()), ev,
324
            p == PROCESS_BROADCAST? "<broadcast>": PROCESS_NAME_STRING(p), nevents);
325
    }
326

327
    if (nevents == PROCESS_CONF_NUMEVENTS) {
100,316✔
328
        #if DEBUG
329
        if (p == PROCESS_BROADCAST) {
330
            printf("soft panic: event queue is full when broadcast event %d was posted from %s\n", ev, PROCESS_NAME_STRING(process_current));
331
        } else {
332
            printf("soft panic: event queue is full when event %d was posted to %s from %s\n", ev, PROCESS_NAME_STRING(p), PROCESS_NAME_STRING(process_current));
333
        }
334
        #endif /* DEBUG */
UNCOV
335
        return PROCESS_ERR_FULL;
×
336
    }
337

338
    snum = (process_num_events_t)(fevent + nevents) % PROCESS_CONF_NUMEVENTS;
100,316✔
339
    events[snum].ev = ev;
100,316✔
340
    events[snum].data = data;
100,316✔
341
    events[snum].p = p;
100,316✔
342
    ++nevents;
100,316✔
343

344
    #if PROCESS_CONF_STATS
345
    if (nevents > process_maxevents) {
346
        process_maxevents = nevents;
347
    }
348
    #endif /* PROCESS_CONF_STATS */
349

350
    return PROCESS_ERR_OK;
100,316✔
351
}
352
/*---------------------------------------------------------------------------*/
353
void
354
process_post_synch(struct process *p, process_event_t ev, process_data_t data) {
52✔
355
    struct process *caller = process_current;
52✔
356

357
    call_process(p, ev, data);
52✔
358
    process_current = caller;
52✔
359
}
52✔
360
/*---------------------------------------------------------------------------*/
361
void
362
process_poll(struct process *p) {
200,516✔
363
    if (p != NULL) {
200,516✔
364
        if (p->state == PROCESS_STATE_RUNNING ||
200,516✔
UNCOV
365
            p->state == PROCESS_STATE_CALLED) {
×
366
            p->needspoll = 1;
200,516✔
367
            poll_requested = 1;
200,516✔
368
        }
369
    }
370
}
200,516✔
371
/*---------------------------------------------------------------------------*/
372
int
373
process_is_running(struct process *p) {
×
374
    return p->state != PROCESS_STATE_NONE;
×
375
}
376
/*---------------------------------------------------------------------------*/
377
/** @} */
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

© 2026 Coveralls, Inc