Subversion Repositories HelenOS-historic

Rev

Rev 1155 | Rev 1407 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 1155 Rev 1392
Line 31... Line 31...
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;
Line 60... Line 70...
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
{
Line 96... Line 114...
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.
Line 140... Line 181...
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;
Line 183... Line 215...
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
}