Skip to content

Commit 8011d5b

Browse files
committed
Create a user app demonstration of a mechanism to work around the missing kernel support for passing an argument to a thread function.
1 parent 714439f commit 8011d5b

File tree

2 files changed

+200
-0
lines changed

2 files changed

+200
-0
lines changed

user/apps/generic_thread/build.mk

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Copyright (c) 2013 The F9 Microkernel Project. All rights reserved.
2+
# Use of this source code is governed by a BSD-style license that can be
3+
# found in the LICENSE file.
4+
5+
user-apps-generic_thread-y = \
6+
main.o

user/apps/generic_thread/main.c

Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
/* Copyright (c) 2013 The F9 Microkernel Project. All rights reserved.
2+
* Use of this source code is governed by a BSD-style license that can be
3+
* found in the LICENSE file.
4+
*/
5+
6+
#include <platform/link.h>
7+
#include <user_runtime.h>
8+
#include <gpioer.h>
9+
#include <l4/ipc.h>
10+
#include <l4/utcb.h>
11+
#include <l4/pager.h>
12+
#include <l4/thread.h>
13+
#include <l4io.h>
14+
15+
#define STACK_SIZE 512
16+
17+
enum { PING_THREAD = 0, PONG_THREAD, PUNG_THREAD, BOSS_THREAD, THREAD_COUNT};
18+
static L4_ThreadId_t threads[THREAD_COUNT] __USER_DATA;
19+
20+
#define LABEL 0x1
21+
22+
23+
#if 0
24+
#define __L4_NUM_MRS 16
25+
typedef unsigned long L4_Word_t;
26+
/*
27+
* Message objects
28+
*/
29+
typedef union {
30+
L4_Word_t raw[__L4_NUM_MRS];
31+
L4_Word_t msg[__L4_NUM_MRS];
32+
L4_MsgTag_t tag;
33+
} L4_Msg_t;
34+
#endif
35+
36+
__USER_TEXT
37+
void *ping_thread(void *arg)
38+
{
39+
L4_MsgTag_t tag;
40+
L4_Msg_t msg;
41+
L4_Word_t count = 0;
42+
43+
L4_Word_t my_thread_id = 0;
44+
L4_Word_t prev_thread_id = 0;
45+
L4_Word_t next_thread_id = 0;
46+
47+
printf("\nping_thread %p\n", L4_MyGlobalId());
48+
tag = L4_Receive(threads[BOSS_THREAD]);
49+
50+
L4_MsgStore(tag, &msg);
51+
my_thread_id = L4_MsgWord(&msg, 0);
52+
prev_thread_id = L4_MsgWord(&msg, 1);
53+
next_thread_id = L4_MsgWord(&msg, 2);
54+
55+
if ( ( ! L4_IpcSucceeded(tag)) || (my_thread_id == prev_thread_id) ) {
56+
printf("\nping_thread - %p: recv ipc fails %d, %d\n", L4_MyGlobalId(), my_thread_id, prev_thread_id);
57+
printf("ping_thread - %p: ErrorCode = 0x%x %s\n", L4_MyGlobalId(), L4_ErrorCode(), L4_ErrorCode_String(L4_ErrorCode()));
58+
59+
return 0;
60+
}
61+
else {
62+
printf("\nping_thread %p %d is initialized : prev_thread_id %d, next_thread_id %d\n", L4_MyGlobalId(), my_thread_id, prev_thread_id, next_thread_id);
63+
}
64+
65+
/* WARNING !!! Cannot do this! Apparently, a message cannot be sent to a thread that is not already waiting for it. */
66+
// L4_Sleep(L4_TimePeriod(500 * 1000));
67+
68+
while (1) {
69+
tag = L4_Receive_Timeout(threads[prev_thread_id], L4_TimePeriod(1000 * 1000));
70+
L4_MsgStore(tag, &msg);
71+
count = L4_MsgWord(&msg, 0);
72+
prev_thread_id = L4_MsgWord(&msg, 1);
73+
74+
if (!L4_IpcSucceeded(tag)) {
75+
printf("\nping_thread - %p: recv ipc fails\n", L4_MyGlobalId());
76+
printf("ping_thread - %p: ErrorCode = 0x%x %s\n", L4_MyGlobalId(), L4_ErrorCode(), L4_ErrorCode_String(L4_ErrorCode()));
77+
}
78+
/* FIXME: workaround solution to avoid scheduler starvation */
79+
L4_Sleep(L4_TimePeriod(500 * 1000));
80+
81+
printf("\nThread # %d received count %d from thread %d, next %d\n", my_thread_id, count, prev_thread_id, next_thread_id);
82+
83+
L4_MsgClear(&msg);
84+
L4_Set_MsgLabel(&msg, LABEL);
85+
L4_MsgAppendWord(&msg, ++count);
86+
L4_MsgAppendWord(&msg, my_thread_id); // prev_thread_id for next thread in the sequence.
87+
L4_MsgAppendWord(&msg, next_thread_id);
88+
L4_MsgLoad(&msg);
89+
90+
tag = L4_Send_Timeout(threads[next_thread_id],
91+
L4_TimePeriod(1000 * 1000));
92+
93+
if (!L4_IpcSucceeded(tag)) {
94+
printf("\nping_thread - %p: send ipc fails\n", L4_MyGlobalId());
95+
printf("ping_thread - %p: ErrorCode = 0x%x %s\n", L4_MyGlobalId(), L4_ErrorCode(), L4_ErrorCode_String(L4_ErrorCode()));
96+
}
97+
/* FIXME: workaround solution to avoid scheduler starvation */
98+
L4_Sleep(L4_TimePeriod(500 * 1000));
99+
}
100+
}
101+
102+
__USER_TEXT
103+
void *boss_thread(void *arg)
104+
{
105+
L4_MsgTag_t tag;
106+
L4_Msg_t msg;
107+
108+
L4_Word_t this_thread;
109+
110+
printf("\nboss_thread() %p is running\n", L4_MyGlobalId());
111+
112+
for (this_thread = PING_THREAD; this_thread < BOSS_THREAD; this_thread++) {
113+
printf("\nCreate thread %d\n", this_thread);
114+
threads[this_thread] = pager_create_thread();
115+
printf("\nStart thread %d\n", this_thread);
116+
pager_start_thread(threads[this_thread], ping_thread, NULL);
117+
}
118+
119+
// Initialize each thread state.
120+
// This is a work-around for lack of support for thread arg parameter.
121+
L4_Word_t prev_thread_id = BOSS_THREAD;
122+
L4_Word_t next_thread_id = PONG_THREAD;
123+
for (this_thread = PING_THREAD; this_thread < BOSS_THREAD; this_thread++) {
124+
125+
printf("\nInitialize thread state %d %d %d\n", prev_thread_id, this_thread, next_thread_id);
126+
127+
L4_MsgClear(&msg);
128+
L4_Set_MsgLabel(&msg, LABEL);
129+
L4_MsgAppendWord(&msg, this_thread);
130+
L4_MsgAppendWord(&msg, prev_thread_id);
131+
L4_MsgAppendWord(&msg, next_thread_id);
132+
L4_MsgLoad(&msg);
133+
134+
tag = L4_Send_Timeout(threads[this_thread], L4_TimePeriod(1000 * 1000));
135+
136+
if (!L4_IpcSucceeded(tag)) {
137+
printf("\nboss_thread() %p: send ipc fails\n", L4_MyGlobalId());
138+
printf("boss_thread() %p: ErrorCode = 0x%x %s\n", L4_MyGlobalId(), L4_ErrorCode(), L4_ErrorCode_String(L4_ErrorCode()));
139+
}
140+
else {
141+
printf("\nping thread %d %p is initialized by boss thread\n", this_thread, threads[this_thread]);
142+
}
143+
144+
prev_thread_id = ((++prev_thread_id >= BOSS_THREAD) ? PING_THREAD : prev_thread_id);
145+
next_thread_id = ((++next_thread_id == BOSS_THREAD) ? PING_THREAD : next_thread_id);
146+
}
147+
148+
// Prime the pump - send a message to kick-off the round-robin pinging among the threads.
149+
{
150+
L4_Word_t count = 0;
151+
152+
printf("\nPrime the pump %d\n", count);
153+
154+
L4_MsgClear(&msg);
155+
L4_Set_MsgLabel(&msg, LABEL);
156+
L4_MsgAppendWord(&msg, count);
157+
L4_MsgAppendWord(&msg, PUNG_THREAD);
158+
L4_MsgLoad(&msg);
159+
160+
tag = L4_Send_Timeout(threads[PING_THREAD], L4_TimePeriod(1000 * 1000));
161+
162+
if (!L4_IpcSucceeded(tag)) {
163+
printf("\nboss_thread() %p: send ipc fails\n", L4_MyGlobalId());
164+
printf("boss_thread() %p: ErrorCode = 0x%x %s\n", L4_MyGlobalId(), L4_ErrorCode(), L4_ErrorCode_String(L4_ErrorCode()));
165+
}
166+
else {
167+
printf("\nPump is primed %d\n", count);
168+
}
169+
}
170+
171+
printf("\nEXITING boot_thread()\n");
172+
return 0;
173+
}
174+
175+
__USER_TEXT
176+
static void *main(void *user)
177+
{
178+
printf("\nmain()\n");
179+
180+
threads[BOSS_THREAD] = pager_create_thread();
181+
pager_start_thread(threads[BOSS_THREAD], boss_thread, NULL);
182+
183+
printf("\nEXITING main()\n");
184+
return 0;
185+
}
186+
187+
// DECLARE_FPAGE(0x0, (number_of_threads * 2 * UTCB_SIZE) + (number_of_threads * 2 * STACK_SIZE))
188+
DECLARE_USER(
189+
0,
190+
generic_thread,
191+
main,
192+
DECLARE_FPAGE(0x0, 8 * UTCB_SIZE + 8 * STACK_SIZE)
193+
DECLARE_FPAGE(0x0, 512)
194+
);

0 commit comments

Comments
 (0)