Skip to content

Commit cd4172a

Browse files
committed
Merge branch 'master' of https://github.com/ARMmbed/mbed-os
2 parents 878ce59 + 451b8c3 commit cd4172a

File tree

10 files changed

+330
-64
lines changed

10 files changed

+330
-64
lines changed
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
#include "mbed.h"
2+
#include "test_env.h"
3+
#include "unity.h"
4+
#include "utest.h"
5+
#include "rtos.h"
6+
7+
8+
using namespace utest::v1;
9+
10+
11+
// Tasks with different functions to test on threads
12+
void increment(const void *var) {
13+
(*(int *)var)++;
14+
}
15+
16+
void increment_with_yield(const void *var) {
17+
Thread::yield();
18+
(*(int *)var)++;
19+
}
20+
21+
void increment_with_wait(const void *var) {
22+
Thread::wait(100);
23+
(*(int *)var)++;
24+
}
25+
26+
void increment_with_child(const void *var) {
27+
Thread child(increment, (void*)var);
28+
child.join();
29+
}
30+
31+
void increment_with_murder(const void *var) {
32+
Thread child(increment_with_wait, (void*)var);
33+
// Kill child before it can increment var
34+
child.terminate();
35+
(*(int *)var)++;
36+
}
37+
38+
39+
// Tests that spawn tasks in different configurations
40+
template <void (*F)(const void *)>
41+
void test_single_thread() {
42+
int var = 0;
43+
Thread thread(F, &var);
44+
thread.join();
45+
TEST_ASSERT_EQUAL(var, 1);
46+
}
47+
48+
template <int N, void (*F)(const void *)>
49+
void test_parallel_threads() {
50+
int var = 0;
51+
Thread *threads[N];
52+
53+
for (int i = 0; i < N; i++) {
54+
threads[i] = new Thread(F, &var);
55+
}
56+
57+
for (int i = 0; i < N; i++) {
58+
threads[i]->join();
59+
delete threads[i];
60+
}
61+
62+
TEST_ASSERT_EQUAL(var, N);
63+
}
64+
65+
template <int N, void (*F)(const void *)>
66+
void test_serial_threads() {
67+
int var = 0;
68+
69+
for (int i = 0; i < N; i++) {
70+
Thread thread(F, &var);
71+
thread.join();
72+
}
73+
74+
TEST_ASSERT_EQUAL(var, N);
75+
}
76+
77+
78+
status_t test_setup(const size_t number_of_cases) {
79+
GREENTEA_SETUP(40, "default_auto");
80+
return verbose_test_setup_handler(number_of_cases);
81+
}
82+
83+
// Test cases
84+
Case cases[] = {
85+
Case("Testing single thread", test_single_thread<increment>),
86+
Case("Testing parallel threads", test_parallel_threads<3, increment>),
87+
Case("Testing serial threads", test_serial_threads<10, increment>),
88+
89+
Case("Testing single thread with yield", test_single_thread<increment_with_yield>),
90+
Case("Testing parallel threads with yield", test_parallel_threads<3, increment_with_yield>),
91+
Case("Testing serial threads with yield", test_serial_threads<10, increment_with_yield>),
92+
93+
Case("Testing single thread with wait", test_single_thread<increment_with_wait>),
94+
Case("Testing parallel threads with wait", test_parallel_threads<3, increment_with_wait>),
95+
Case("Testing serial threads with wait", test_serial_threads<10, increment_with_wait>),
96+
97+
Case("Testing single thread with child", test_single_thread<increment_with_child>),
98+
Case("Testing parallel threads with child", test_parallel_threads<3, increment_with_child>),
99+
Case("Testing serial threads with child", test_serial_threads<10, increment_with_child>),
100+
101+
Case("Testing single thread with murder", test_single_thread<increment_with_murder>),
102+
Case("Testing parallel threads with murder", test_parallel_threads<3, increment_with_murder>),
103+
Case("Testing serial threads with murder", test_serial_threads<10, increment_with_murder>),
104+
};
105+
106+
Specification specification(test_setup, cases);
107+
108+
int main() {
109+
return !Harness::run(specification);
110+
}

core/mbed-rtos/rtos/Thread.cpp

Lines changed: 59 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,34 +26,82 @@
2626

2727
namespace rtos {
2828

29+
Thread::Thread(osPriority priority,
30+
uint32_t stack_size, unsigned char *stack_pointer):
31+
_tid(NULL), _dynamic_stack(stack_pointer == NULL) {
32+
#ifdef __MBED_CMSIS_RTOS_CM
33+
_thread_def.tpriority = priority;
34+
_thread_def.stacksize = stack_size;
35+
_thread_def.stack_pointer = (uint32_t*)stack_pointer;
36+
#endif
37+
}
38+
2939
Thread::Thread(void (*task)(void const *argument), void *argument,
30-
osPriority priority, uint32_t stack_size, unsigned char *stack_pointer) {
40+
osPriority priority, uint32_t stack_size, unsigned char *stack_pointer):
41+
_tid(NULL), _dynamic_stack(stack_pointer == NULL) {
3142
#ifdef __MBED_CMSIS_RTOS_CM
32-
_thread_def.pthread = task;
3343
_thread_def.tpriority = priority;
3444
_thread_def.stacksize = stack_size;
35-
if (stack_pointer != NULL) {
36-
_thread_def.stack_pointer = (uint32_t*)stack_pointer;
37-
_dynamic_stack = false;
38-
} else {
39-
_thread_def.stack_pointer = new uint32_t[stack_size/sizeof(uint32_t)];
40-
if (_thread_def.stack_pointer == NULL)
45+
_thread_def.stack_pointer = (uint32_t*)stack_pointer;
46+
#endif
47+
switch(start(task, argument)) {
48+
case osErrorResource:
49+
error("OS ran out of threads!\n");
50+
break;
51+
case osErrorParameter:
52+
error("Thread already running!\n");
53+
break;
54+
case osErrorNoMemory:
4155
error("Error allocating the stack memory\n");
42-
_dynamic_stack = true;
56+
default:
57+
break;
58+
}
59+
}
60+
61+
osStatus Thread::start(void (*task)(void const *argument), void *argument) {
62+
if (_tid != NULL) {
63+
return osErrorParameter;
4364
}
44-
65+
66+
#ifdef __MBED_CMSIS_RTOS_CM
67+
_thread_def.pthread = task;
68+
if (_thread_def.stack_pointer == NULL) {
69+
_thread_def.stack_pointer = new uint32_t[_thread_def.stacksize/sizeof(uint32_t)];
70+
if (_thread_def.stack_pointer == NULL)
71+
return osErrorNoMemory;
72+
}
73+
4574
//Fill the stack with a magic word for maximum usage checking
46-
for (uint32_t i = 0; i < (stack_size / sizeof(uint32_t)); i++) {
75+
for (uint32_t i = 0; i < (_thread_def.stacksize / sizeof(uint32_t)); i++) {
4776
_thread_def.stack_pointer[i] = 0xE25A2EA5;
4877
}
4978
#endif
5079
_tid = osThreadCreate(&_thread_def, argument);
80+
if (_tid == NULL) {
81+
if (_dynamic_stack) delete[] (_thread_def.stack_pointer);
82+
return osErrorResource;
83+
}
84+
return osOK;
5185
}
5286

5387
osStatus Thread::terminate() {
5488
return osThreadTerminate(_tid);
5589
}
5690

91+
osStatus Thread::join() {
92+
while (true) {
93+
uint8_t state = get_state();
94+
if (state == Thread::Inactive || state == osErrorParameter) {
95+
return osOK;
96+
}
97+
98+
osStatus status = yield();
99+
if (status != osOK) {
100+
return status;
101+
}
102+
}
103+
}
104+
57105
osStatus Thread::set_priority(osPriority priority) {
58106
return osThreadSetPriority(_tid, priority);
59107
}

core/mbed-rtos/rtos/Thread.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,15 @@ namespace rtos {
3030
/** The Thread class allow defining, creating, and controlling thread functions in the system. */
3131
class Thread {
3232
public:
33+
/** Allocate a new thread without starting execution
34+
@param priority initial priority of the thread function. (default: osPriorityNormal).
35+
@param stack_size stack size (in bytes) requirements for the thread function. (default: DEFAULT_STACK_SIZE).
36+
@param stack_pointer pointer to the stack area to be used by this thread (default: NULL).
37+
*/
38+
Thread(osPriority priority=osPriorityNormal,
39+
uint32_t stack_size=DEFAULT_STACK_SIZE,
40+
unsigned char *stack_pointer=NULL);
41+
3342
/** Create a new thread, and start it executing the specified function.
3443
@param task function to be executed by this thread.
3544
@param argument pointer that is passed to the thread function as start argument. (default: NULL).
@@ -42,6 +51,19 @@ class Thread {
4251
uint32_t stack_size=DEFAULT_STACK_SIZE,
4352
unsigned char *stack_pointer=NULL);
4453

54+
/** Starts a thread executing the specified function.
55+
@param task function to be executed by this thread.
56+
@param argument pointer that is passed to the thread function as start argument. (default: NULL).
57+
@return status code that indicates the execution status of the function.
58+
*/
59+
osStatus start(void (*task)(void const *argument), void *argument=NULL);
60+
61+
/** Wait for thread to terminate
62+
@return status code that indicates the execution status of the function.
63+
@note not callable from interrupt
64+
*/
65+
osStatus join();
66+
4567
/** Terminate execution of a thread and remove it from Active Threads
4668
@return status code that indicates the execution status of the function.
4769
*/
@@ -113,17 +135,20 @@ class Thread {
113135
@param signals wait until all specified signal flags set or 0 for any single signal flag.
114136
@param millisec timeout value or 0 in case of no time-out. (default: osWaitForever).
115137
@return event flag information or error code.
138+
@note not callable from interrupt
116139
*/
117140
static osEvent signal_wait(int32_t signals, uint32_t millisec=osWaitForever);
118141

119142
/** Wait for a specified time period in millisec:
120143
@param millisec time delay value
121144
@return status code that indicates the execution status of the function.
145+
@note not callable from interrupt
122146
*/
123147
static osStatus wait(uint32_t millisec);
124148

125149
/** Pass control to next thread that is in state READY.
126150
@return status code that indicates the execution status of the function.
151+
@note not callable from interrupt
127152
*/
128153
static osStatus yield();
129154

tools/test.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727

2828
from tools.test_api import test_path_to_name, find_tests, print_tests, build_tests, test_spec_from_test_build
2929
from tools.options import get_default_options_parser
30-
from tools.build_api import build_project
30+
from tools.build_api import build_project, build_library
3131
from tools.targets import TARGET_MAP
3232
from tools.utils import mkdir
3333

@@ -115,10 +115,17 @@
115115
if not base_source_paths:
116116
base_source_paths = ['.']
117117

118+
118119
target = TARGET_MAP[options.mcu]
119120

121+
lib_build_res = build_library(base_source_paths, options.build_dir, target, options.tool,
122+
options=options.options,
123+
jobs=options.jobs,
124+
clean=options.clean,
125+
archive=False)
126+
120127
# Build all the tests
121-
test_build = build_tests(tests, base_source_paths, options.build_dir, target, options.tool,
128+
test_build = build_tests(tests, [options.build_dir], options.build_dir, target, options.tool,
122129
options=options.options,
123130
clean=options.clean,
124131
jobs=options.jobs)

tools/test_api.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2041,13 +2041,13 @@ def build_tests(tests, base_source_paths, build_path, target, toolchain_name,
20412041
}
20422042

20432043
for test_name, test_path in tests.iteritems():
2044+
test_build_path = os.path.join(build_path, test_path)
20442045
src_path = base_source_paths + [test_path]
2045-
artifact_name = os.path.join(test_path, test_name)
2046-
bin_file = build_project(src_path, build_path, target, toolchain_name,
2046+
bin_file = build_project(src_path, test_build_path, target, toolchain_name,
20472047
options=options,
20482048
jobs=jobs,
20492049
clean=clean,
2050-
name=artifact_name,
2050+
name=test_name,
20512051
report=report,
20522052
properties=properties,
20532053
verbose=verbose)

0 commit comments

Comments
 (0)