Subversion Repositories HelenOS-historic

Rev

Rev 1155 | Rev 1407 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 1155 Rev 1392
1
/*
1
/*
2
 * Copyright (C) 2006 Ondrej Palkovsky
2
 * Copyright (C) 2006 Ondrej Palkovsky
3
 * All rights reserved.
3
 * All rights reserved.
4
 *
4
 *
5
 * Redistribution and use in source and binary forms, with or without
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
6
 * modification, are permitted provided that the following conditions
7
 * are met:
7
 * are met:
8
 *
8
 *
9
 * - Redistributions of source code must retain the above copyright
9
 * - Redistributions of source code must retain the above copyright
10
 *   notice, this list of conditions and the following disclaimer.
10
 *   notice, this list of conditions and the following disclaimer.
11
 * - Redistributions in binary form must reproduce the above copyright
11
 * - Redistributions in binary form must reproduce the above copyright
12
 *   notice, this list of conditions and the following disclaimer in the
12
 *   notice, this list of conditions and the following disclaimer in the
13
 *   documentation and/or other materials provided with the distribution.
13
 *   documentation and/or other materials provided with the distribution.
14
 * - The name of the author may not be used to endorse or promote products
14
 * - The name of the author may not be used to endorse or promote products
15
 *   derived from this software without specific prior written permission.
15
 *   derived from this software without specific prior written permission.
16
 *
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
 */
27
 */
28
 
28
 
29
#include <libadt/list.h>
29
#include <libadt/list.h>
30
#include <psthread.h>
30
#include <psthread.h>
31
#include <malloc.h>
31
#include <malloc.h>
32
#include <unistd.h>
32
#include <unistd.h>
33
#include <thread.h>
33
#include <thread.h>
34
#include <stdio.h>
34
#include <stdio.h>
35
#include <kernel/arch/faddr.h>
35
#include <kernel/arch/faddr.h>
36
 
-
 
-
 
36
#include <futex.h>
-
 
37
#include <assert.h>
37
 
38
 
38
#ifndef PSTHREAD_INITIAL_STACK_PAGES_NO
39
#ifndef PSTHREAD_INITIAL_STACK_PAGES_NO
39
#define PSTHREAD_INITIAL_STACK_PAGES_NO 1
40
#define PSTHREAD_INITIAL_STACK_PAGES_NO 1
40
#endif
41
#endif
41
 
42
 
42
static LIST_INITIALIZE(ready_list);
43
static LIST_INITIALIZE(ready_list);
-
 
44
static LIST_INITIALIZE(manager_list);
43
 
45
 
44
static void psthread_exit(void) __attribute__ ((noinline));
46
static void psthread_exit(void) __attribute__ ((noinline));
45
static void psthread_main(void);
47
static void psthread_main(void);
46
 
48
 
-
 
49
static atomic_t psthread_futex = FUTEX_INITIALIZER;
-
 
50
 
47
/** Setup PSthread information into TCB structure */
51
/** Setup PSthread information into TCB structure */
48
psthread_data_t * psthread_setup(tcb_t *tcb)
52
psthread_data_t * psthread_setup()
49
{
53
{
50
    psthread_data_t *pt;
54
    psthread_data_t *pt;
-
 
55
    tcb_t *tcb;
-
 
56
 
-
 
57
    tcb = __make_tls();
-
 
58
    if (!tcb)
-
 
59
        return NULL;
51
 
60
 
52
    pt = malloc(sizeof(*pt));
61
    pt = malloc(sizeof(*pt));
53
    if (!pt) {
62
    if (!pt) {
-
 
63
        __free_tls(tcb);
54
        return NULL;
64
        return NULL;
55
    }
65
    }
56
 
66
 
57
    tcb->pst_data = pt;
67
    tcb->pst_data = pt;
58
    pt->tcb = tcb;
68
    pt->tcb = tcb;
59
 
69
 
60
    return pt;
70
    return pt;
61
}
71
}
62
 
72
 
63
void psthread_teardown(psthread_data_t *pt)
73
void psthread_teardown(psthread_data_t *pt)
64
{
74
{
-
 
75
    __free_tls(pt->tcb);
65
    free(pt);
76
    free(pt);
66
}
77
}
67
 
78
 
68
/** Function to preempt to other pseudo thread without adding
79
/** Function to preempt to other pseudo thread without adding
69
 * currently running pseudo thread to ready_list.
80
 * currently running pseudo thread to ready_list.
70
 */
81
 */
71
void psthread_exit(void)
82
void psthread_exit(void)
72
{
83
{
73
    psthread_data_t *pt;
84
    psthread_data_t *pt;
74
 
85
 
-
 
86
    futex_down(&psthread_futex);
-
 
87
 
75
    if (list_empty(&ready_list)) {
88
    if (!list_empty(&ready_list))
-
 
89
        pt = list_get_instance(ready_list.next, psthread_data_t, link);
76
        /* Wait on IPC queue etc... */
90
    else if (!list_empty(&manager_list))
-
 
91
        pt = list_get_instance(manager_list.next, psthread_data_t, link);
-
 
92
    else {
77
        printf("Cannot exit!!!\n");
93
        printf("Cannot find suitable psthread to run.\n");
78
        _exit(0);
94
        _exit(0);
79
    }
95
    }
80
    pt = list_get_instance(ready_list.next, psthread_data_t, link);
-
 
81
    list_remove(&pt->link);
96
    list_remove(&pt->link);
-
 
97
    futex_up(&psthread_futex);
-
 
98
 
82
    context_restore(&pt->ctx);
99
    context_restore(&pt->ctx);
-
 
100
    /* Never reached */
83
}
101
}
84
 
102
 
85
/** Function that is called on entry to new uspace thread */
103
/** Function that is called on entry to new uspace thread */
86
void psthread_main(void)
104
void psthread_main(void)
87
{
105
{
88
    psthread_data_t *pt = __tcb_get()->pst_data;
106
    psthread_data_t *pt = __tcb_get()->pst_data;
89
 
107
 
90
    pt->retval = pt->func(pt->arg);
108
    pt->retval = pt->func(pt->arg);
91
 
109
 
92
    pt->finished = 1;
110
    pt->finished = 1;
93
    if (pt->waiter)
111
    if (pt->waiter)
94
        list_append(&pt->waiter->link, &ready_list);
112
        list_append(&pt->waiter->link, &ready_list);
95
 
113
 
96
    psthread_exit();
114
    psthread_exit();
97
}
115
}
98
 
116
 
99
/** Schedule next userspace pseudo thread.
117
/** Schedule next userspace pseudo thread.
100
 *
118
 *
-
 
119
 * @param tomanager If true, we are switching to next ready manager thread
-
 
120
 *                  (if none is found, thread is exited)
-
 
121
 * @param frommanager If true, we are switching from manager thread
101
 * @return 0 if there is no ready pseudo thread, 1 otherwise.
122
 * @return 0 if there is no ready pseudo thread, 1 otherwise.
102
 */
123
 */
103
int psthread_schedule_next(void)
124
int psthread_schedule_next_adv(pschange_type ctype)
104
{
125
{
105
    psthread_data_t *pt;
126
    psthread_data_t *pt;
-
 
127
    int retval = 0;
-
 
128
   
-
 
129
    futex_down(&psthread_futex);
106
 
130
 
107
    if (list_empty(&ready_list))
131
    if (ctype == PS_PREEMPT && list_empty(&ready_list))
108
        return 0;
132
        goto ret_0;
-
 
133
 
-
 
134
    if (ctype == PS_FROM_MANAGER && list_empty(&ready_list)) {
-
 
135
        goto ret_0;
-
 
136
    }
-
 
137
    assert(!(ctype == PS_TO_MANAGER && list_empty(&manager_list)));
109
 
138
 
110
    pt = __tcb_get()->pst_data;
139
    pt = __tcb_get()->pst_data;
111
    if (!context_save(&pt->ctx))
140
    if (!context_save(&pt->ctx))
112
        return 1;
141
        return 1; // futex_up already done here
-
 
142
 
-
 
143
    if (ctype == PS_PREEMPT)
-
 
144
        list_append(&pt->link, &ready_list);
-
 
145
    else if (ctype == PS_FROM_MANAGER)
-
 
146
        list_append(&pt->link, &manager_list);
113
   
147
   
-
 
148
    if (ctype == PS_TO_MANAGER)
114
    list_append(&pt->link, &ready_list);
149
        pt = list_get_instance(manager_list.next,psthread_data_t, link);
-
 
150
    else
115
    pt = list_get_instance(ready_list.next, psthread_data_t, link);
151
        pt = list_get_instance(ready_list.next, psthread_data_t, link);
116
    list_remove(&pt->link);
152
    list_remove(&pt->link);
117
 
153
 
-
 
154
    futex_up(&psthread_futex);
118
    context_restore(&pt->ctx);
155
    context_restore(&pt->ctx);
-
 
156
 
-
 
157
ret_0:
-
 
158
    futex_up(&psthread_futex);
-
 
159
    return retval;
119
}
160
}
120
 
161
 
121
/** Wait for uspace pseudo thread to finish.
162
/** Wait for uspace pseudo thread to finish.
122
 *
163
 *
123
 * @param psthrid Pseudo thread to wait for.
164
 * @param psthrid Pseudo thread to wait for.
124
 *
165
 *
125
 * @return Value returned by the finished thread.
166
 * @return Value returned by the finished thread.
126
 */
167
 */
127
int psthread_join(pstid_t psthrid)
168
int psthread_join(pstid_t psthrid)
128
{
169
{
129
    volatile psthread_data_t *pt, *mypt;
170
    volatile psthread_data_t *pt, *mypt;
130
    volatile int retval;
171
    volatile int retval;
131
 
172
 
132
    /* Handle psthrid = Kernel address -> it is wait for call */
173
    /* Handle psthrid = Kernel address -> it is wait for call */
133
    pt = (psthread_data_t *) psthrid;
174
    pt = (psthread_data_t *) psthrid;
134
 
175
 
135
    if (!pt->finished) {
176
    if (!pt->finished) {
136
        mypt = __tcb_get()->pst_data;
177
        mypt = __tcb_get()->pst_data;
137
        if (context_save(&((psthread_data_t *) mypt)->ctx)) {
178
        if (context_save(&((psthread_data_t *) mypt)->ctx)) {
138
            pt->waiter = (psthread_data_t *) mypt;
179
            pt->waiter = (psthread_data_t *) mypt;
139
            psthread_exit();
180
            psthread_exit();
140
        }
181
        }
141
    }
182
    }
142
    retval = pt->retval;
183
    retval = pt->retval;
143
 
184
 
144
    free(pt->stack);
185
    free(pt->stack);
145
    __free_tls(pt->tcb);
-
 
146
    psthread_teardown((void *)pt);
186
    psthread_teardown((void *)pt);
147
 
187
 
148
    return retval;
188
    return retval;
149
}
189
}
150
 
190
 
151
/**
191
/**
152
 * Create a userspace thread and append it to ready list.
192
 * Create a userspace thread
153
 *
193
 *
154
 * @param func Pseudo thread function.
194
 * @param func Pseudo thread function.
155
 * @param arg Argument to pass to func.
195
 * @param arg Argument to pass to func.
156
 *
196
 *
157
 * @return 0 on failure, TLS of the new pseudo thread.
197
 * @return 0 on failure, TLS of the new pseudo thread.
158
 */
198
 */
159
pstid_t psthread_create(int (*func)(void *), void *arg)
199
pstid_t psthread_create(int (*func)(void *), void *arg)
160
{
200
{
161
    psthread_data_t *pt;
201
    psthread_data_t *pt;
162
    tcb_t *tcb;
-
 
163
 
-
 
164
    tcb = __make_tls();
-
 
165
    if (!tcb)
-
 
166
        return 0;
-
 
167
 
202
 
168
    pt = psthread_setup(tcb);
203
    pt = psthread_setup();
169
    if (!pt) {
204
    if (!pt)
170
        __free_tls(tcb);
-
 
171
        return 0;
205
        return 0;
172
    }
-
 
173
    pt->stack = (char *) malloc(PSTHREAD_INITIAL_STACK_PAGES_NO*getpagesize());
206
    pt->stack = (char *) malloc(PSTHREAD_INITIAL_STACK_PAGES_NO*getpagesize());
174
 
207
 
175
    if (!pt->stack) {
208
    if (!pt->stack) {
176
        __free_tls(tcb);
-
 
177
        psthread_teardown(pt);
209
        psthread_teardown(pt);
178
        return 0;
210
        return 0;
179
    }
211
    }
180
 
212
 
181
    pt->arg= arg;
213
    pt->arg= arg;
182
    pt->func = func;
214
    pt->func = func;
183
    pt->finished = 0;
215
    pt->finished = 0;
184
    pt->waiter = NULL;
216
    pt->waiter = NULL;
185
 
217
 
186
    context_save(&pt->ctx);
218
    context_save(&pt->ctx);
187
    context_set(&pt->ctx, FADDR(psthread_main), pt->stack, PSTHREAD_INITIAL_STACK_PAGES_NO*getpagesize(),
219
    context_set(&pt->ctx, FADDR(psthread_main), pt->stack, PSTHREAD_INITIAL_STACK_PAGES_NO*getpagesize(),
188
            tcb);
220
            pt->tcb);
-
 
221
 
-
 
222
    return (pstid_t )pt;
-
 
223
}
-
 
224
 
-
 
225
/** Add a thread to ready list */
-
 
226
void psthread_add_ready(pstid_t psthrid)
-
 
227
{
-
 
228
    psthread_data_t *pt;
189
 
229
 
-
 
230
    pt = (psthread_data_t *) psthrid;
-
 
231
    futex_down(&psthread_futex);
190
    list_append(&pt->link, &ready_list);
232
    list_append(&pt->link, &ready_list);
-
 
233
    futex_up(&psthread_futex);
-
 
234
}
191
 
235
 
-
 
236
/** Add a thread to manager list */
-
 
237
void psthread_add_manager(pstid_t psthrid)
-
 
238
{
192
    return (pstid_t )pt;
239
    psthread_data_t *pt;
-
 
240
 
-
 
241
    pt = (psthread_data_t *) psthrid;
-
 
242
 
-
 
243
    futex_down(&psthread_futex);
-
 
244
    list_append(&pt->link, &manager_list);
-
 
245
    futex_up(&psthread_futex);
-
 
246
}
-
 
247
 
-
 
248
/** Remove one manager from manager list */
-
 
249
void psthread_remove_manager()
-
 
250
{
-
 
251
    futex_down(&psthread_futex);
-
 
252
    if (list_empty(&manager_list)) {
-
 
253
        printf("No manager found!.\n");
-
 
254
        futex_up(&psthread_futex);
-
 
255
        return;
-
 
256
    }
-
 
257
    list_remove(manager_list.next);
-
 
258
    futex_up(&psthread_futex);
193
}
259
}
194
 
260