Subversion Repositories HelenOS

Rev

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

Rev 2296 Rev 2309
1
/*
1
/*
2
 * Copyright (c) 2007 Jan Hudecek
2
 * Copyright (c) 2007 Jan Hudecek
3
 * Copyright (c) 2006 Jakub Jermar
3
 * Copyright (c) 2006 Jakub Jermar
4
 * All rights reserved.
4
 * All rights reserved.
5
 *
5
 *
6
 * Redistribution and use in source and binary forms, with or without
6
 * Redistribution and use in source and binary forms, with or without
7
 * modification, are permitted provided that the following conditions
7
 * modification, are permitted provided that the following conditions
8
 * are met:
8
 * are met:
9
 *
9
 *
10
 * - Redistributions of source code must retain the above copyright
10
 * - Redistributions of source code must retain the above copyright
11
 *   notice, this list of conditions and the following disclaimer.
11
 *   notice, this list of conditions and the following disclaimer.
12
 * - Redistributions in binary form must reproduce the above copyright
12
 * - Redistributions in binary form must reproduce the above copyright
13
 *   notice, this list of conditions and the following disclaimer in the
13
 *   notice, this list of conditions and the following disclaimer in the
14
 *   documentation and/or other materials provided with the distribution.
14
 *   documentation and/or other materials provided with the distribution.
15
 * - The name of the author may not be used to endorse or promote products
15
 * - The name of the author may not be used to endorse or promote products
16
 *   derived from this software without specific prior written permission.
16
 *   derived from this software without specific prior written permission.
17
 *
17
 *
18
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
 */
28
 */
29
 
29
 
30
/** @addtogroup genericddi
30
/** @addtogroup genericddi
31
 * @{
31
 * @{
32
 */
32
 */
33
/** @file
33
/** @file
34
 */
34
 */
35
 
35
 
36
#include <arch.h>
36
#include <arch.h>
37
#include <config.h>
37
#include <config.h>
38
#include <arch/types.h>
38
#include <arch/types.h>
39
#include <arch/asm.h>
39
#include <arch/asm.h>
40
#include <proc/tasklet.h>
40
#include <proc/tasklet.h>
41
#include <synch/spinlock.h>
41
#include <synch/spinlock.h>
42
#include <time/delay.h>
42
#include <time/delay.h>
43
#include <proc/thread.h>
43
#include <proc/thread.h>
44
#include <panic.h>
44
#include <panic.h>
45
#include <print.h>
45
#include <print.h>
46
#include <synch/waitq.h>
46
#include <synch/waitq.h>
47
#include <cpu.h>
47
#include <cpu.h>
48
#include <proc/scheduler.h>
48
#include <proc/scheduler.h>
49
 
49
 
50
/** Timeout length in the tasklet thread */
50
/** Timeout length in the tasklet thread */
51
#define TASKLET_THREAD_SLEEPDELAY 10000
51
#define TASKLET_THREAD_SLEEPDELAY 10000
52
///** Priority of the tasklet thread */
52
///** Priority of the tasklet thread */
53
#define TASKLET_THREAD_PRIORITY 1
53
#define TASKLET_THREAD_PRIORITY 1
54
 
54
 
55
 
55
 
56
/** Tasklet state enum */
56
/** Tasklet state enum */
57
typedef enum  {
57
typedef enum  {
58
TASKLET_STATE_NOTACTIVE = 0,
58
TASKLET_STATE_NOTACTIVE = 0,
59
TASKLET_STATE_SCHEDULED = 1,
59
TASKLET_STATE_SCHEDULED = 1,
60
TASKLET_STATE_RUNNING = 2,
60
TASKLET_STATE_RUNNING = 2,
61
TASKLET_STATE_DISABLED = 4
61
TASKLET_STATE_DISABLED = 4
62
} tasklet_state_enum;
62
} tasklet_state_enum;
63
 
63
 
64
/** Spinlock protecting list of tasklets */
64
/** Spinlock protecting list of tasklets */
65
SPINLOCK_INITIALIZE(tasklet_lock);
65
SPINLOCK_INITIALIZE(tasklet_lock);
66
 
66
 
67
/** array of tasklet lists for every CPU */
67
/** array of tasklet lists for every CPU */
68
tasklet_descriptor_t** tasklet_list;
68
tasklet_descriptor_t** tasklet_list;
69
 
69
 
70
/** Initializes tasklets - except for the tasklet thread */
70
/** Initializes tasklets - except for the tasklet thread */
71
void tasklet_init(void)
71
void tasklet_init(void)
72
{
72
{
73
    int i;
73
    int i;
74
    tasklet_list=malloc(sizeof(tasklet_descriptor_t*)*config.cpu_count,0);
74
    tasklet_list=malloc(sizeof(tasklet_descriptor_t*)*config.cpu_count,0);
75
    if (tasklet_list==0)
75
    if (tasklet_list==0)
76
        panic_printf("tasklet list mem not allocated\n");
76
        panic_printf("tasklet list mem not allocated\n");
77
    for(i=0;i<config.cpu_count;i++) {
77
    for(i=0;i<config.cpu_count;i++) {
78
        tasklet_list[i]=0;
78
        tasklet_list[i]=0;
79
    }
79
    }
80
    spinlock_initialize(&tasklet_lock, "tasklet_lock");
80
    spinlock_initialize(&tasklet_lock, "tasklet_lock");
81
 
81
 
82
}
82
}
83
 
83
 
84
/**
84
/**
85
* Creates and runs the tasklet thread
85
* Creates and runs the tasklet thread
86
*
86
*
87
*  @param kernel_task Pointer to the kernel task - for create_thread
87
*  @param kernel_task Pointer to the kernel task - for create_thread
88
*/
88
*/
89
void tasklet_run_tasklet_thread(task_t * kernel_task)
89
void tasklet_run_tasklet_thread(task_t * kernel_task)
90
{
90
{
91
    //create the tasklet_thread, it's wired to the current cpu, we'll migrate it ourselves
91
    //create the tasklet_thread, it's wired to the current cpu, we'll migrate it ourselves
92
    thread_t* t= thread_create(&tasklet_thread, NULL, kernel_task, THREAD_FLAG_WIRED, "tasklet_thread", false);
92
    thread_t* t= thread_create(&tasklet_thread, NULL, kernel_task, THREAD_FLAG_WIRED, "tasklet_thread", false);
93
    if (t==NULL) {
93
    if (t==NULL) {
94
        //wtf?
94
        //wtf?
95
        panic_printf("tasklet thread not created\n");
95
        panic_printf("tasklet thread not created\n");
96
    } else {
96
    } else {
97
        spinlock_lock(&t->lock);           
97
        spinlock_lock(&t->lock);           
98
        t->cpu = &cpus[0];
98
        t->cpu = &cpus[0];
99
        t->priority = TASKLET_THREAD_PRIORITY;
99
        t->priority = TASKLET_THREAD_PRIORITY;
100
        spinlock_unlock(&t->lock);
100
        spinlock_unlock(&t->lock);
101
        thread_ready(t);
101
        thread_ready(t);
102
    }
102
    }
103
}
103
}
104
 
104
 
105
/** Thread which keeps executing scheduled enabled tasklets
105
/** Thread which keeps executing scheduled enabled tasklets
106
* @param data not used
106
* @param data not used
107
*/
107
*/
108
void tasklet_thread(void* data)
108
void tasklet_thread(void* data)
109
{
109
{
110
#ifdef CONFIG_SMP
110
#ifdef CONFIG_SMP
111
    int current_cpu, new_cpu ;
111
    int current_cpu, new_cpu ;
112
    cpu_t *cpu;
112
    cpu_t *cpu;
113
#endif
113
#endif
114
    waitq_t  wq;
114
    waitq_t  wq;
115
    waitq_initialize(&wq);
115
    waitq_initialize(&wq);
116
   
116
   
117
    while (true) {
117
    while (true) {
118
        tasklet_do();
118
        tasklet_do();
119
#ifdef CONFIG_SMP
119
#ifdef CONFIG_SMP
120
        if (config.cpu_active>1) {
120
        if (config.cpu_active>1) {
121
            current_cpu = CPU->id;
121
            current_cpu = CPU->id;
122
            //find the first cpu with nonempty tasklet_list 
122
            //find the first cpu with nonempty tasklet_list 
123
            for (new_cpu = (current_cpu + 1) % config.cpu_active; new_cpu!=current_cpu && tasklet_list[new_cpu]==0;
123
            for (new_cpu = (current_cpu + 1) % config.cpu_active; new_cpu!=current_cpu && tasklet_list[new_cpu]==0;
124
                    new_cpu=(new_cpu + 1)% config.cpu_active);
124
                    new_cpu=(new_cpu + 1)% config.cpu_active);
125
 
125
 
126
            if (new_cpu!=current_cpu) {
126
            if (new_cpu!=current_cpu) {
127
                //we need to migrate this thread to CPU with id new_cpu
127
                //we need to migrate this thread to CPU with id new_cpu
128
                cpu = &cpus[new_cpu];
128
                cpu = &cpus[new_cpu];
129
 
129
 
130
                spinlock_lock(&THREAD->lock);
130
                spinlock_lock(&THREAD->lock);
131
                //put tasklet_thread on the new_cpu 
131
                //put tasklet_thread on the new_cpu 
132
                THREAD->cpu = cpu;
132
                THREAD->cpu = cpu;
133
                spinlock_unlock(&THREAD->lock);
133
                spinlock_unlock(&THREAD->lock);
134
            }
134
            }
135
        }
135
        }
136
#endif
136
#endif
137
        waitq_sleep_timeout(&wq, (uint32_t)TASKLET_THREAD_SLEEPDELAY, 0);
137
        waitq_sleep_timeout(&wq, (uint32_t)TASKLET_THREAD_SLEEPDELAY, 0);
138
 
138
 
139
 
139
 
140
    }
140
    }
141
}
141
}
142
 
142
 
143
/** Initializes tasklet structure
143
/** Initializes tasklet structure
144
* @param func tasklet callback function to be called
144
* @param func tasklet callback function to be called
145
* @param data pointer to be passed to the tasklet function
145
* @param data pointer to be passed to the tasklet function
146
*/
146
*/
147
tasklet_descriptor_t* tasklet_register(void (*func)(void* data), void* data)
147
tasklet_descriptor_t* tasklet_register(void (*func)(void* data), void* data)
148
{
148
{
149
    tasklet_descriptor_t* tasklet=malloc(sizeof(tasklet_descriptor_t),0);
149
    tasklet_descriptor_t* tasklet=malloc(sizeof(tasklet_descriptor_t),0);
150
    tasklet->data = data;
150
    tasklet->data = data;
151
    tasklet->func = func;
151
    tasklet->func = func;
152
    tasklet->state = TASKLET_STATE_NOTACTIVE;
152
    tasklet->state = TASKLET_STATE_NOTACTIVE;
153
    tasklet->next = 0;
153
    tasklet->next = 0;
154
    return tasklet;
154
    return tasklet;
155
}
155
}
156
 
156
 
157
/** Schedules the tasklet for execution on current CPU
157
/** Schedules the tasklet for execution on current CPU
158
* @param t tasklet to be scheduled
158
* @param t tasklet to be scheduled
159
*/
159
*/
160
void tasklet_schedule(tasklet_descriptor_t* t)
160
void tasklet_schedule(tasklet_descriptor_t* t)
161
{
161
{
-
 
162
    tasklet_schedule_SMP(t, CPU->id);
-
 
163
}
-
 
164
 
-
 
165
/** Schedules the tasklet for execution on id CPU
-
 
166
* @param t tasklet to be scheduled
-
 
167
* @param id CPU id on which the tasklet will be scheduled
-
 
168
*/
-
 
169
void tasklet_schedule_SMP(tasklet_descriptor_t* t, uint32_t id)
-
 
170
{
162
    spinlock_lock(&tasklet_lock);
171
    spinlock_lock(&tasklet_lock);
163
    //clear notactive, running and scheduled flags
172
    //clear notactive, running and scheduled flags
164
    t->state &= TASKLET_STATE_DISABLED;
173
    t->state &= TASKLET_STATE_DISABLED;
165
    //set the scheduled flag
174
    //set the scheduled flag
166
    t->state |= TASKLET_STATE_SCHEDULED;
175
    t->state |= TASKLET_STATE_SCHEDULED;
167
    t->next=tasklet_list[CPU->id];
176
    t->next=tasklet_list[id];
168
    tasklet_list[CPU->id]=t;
177
    tasklet_list[id]=t;
169
    spinlock_unlock(&tasklet_lock);
178
    spinlock_unlock(&tasklet_lock);
170
}
179
}
171
 
180
 
172
/** Tasklet will not be run, even if scheduled
181
/** Tasklet will not be run, even if scheduled
173
* @param t tasklet to be disabled
182
* @param t tasklet to be disabled
174
*/
183
*/
175
void tasklet_disable(tasklet_descriptor_t* t)
184
void tasklet_disable(tasklet_descriptor_t* t)
176
{
185
{
177
    spinlock_lock(&tasklet_lock);
186
    spinlock_lock(&tasklet_lock);
178
    //set the disabled flag
187
    //set the disabled flag
179
    t->state |= TASKLET_STATE_DISABLED;
188
    t->state |= TASKLET_STATE_DISABLED;
180
    spinlock_unlock(&tasklet_lock);
189
    spinlock_unlock(&tasklet_lock);
181
}
190
}
182
 
191
 
183
/** Tasklet will be run if scheduled
192
/** Tasklet will be run if scheduled
184
* @param t tasklet to be enabled
193
* @param t tasklet to be enabled
185
*/
194
*/
186
void tasklet_enable(tasklet_descriptor_t* t)
195
void tasklet_enable(tasklet_descriptor_t* t)
187
{
196
{
188
    spinlock_lock(&tasklet_lock);
197
    spinlock_lock(&tasklet_lock);
189
    //clear the disabled flag
198
    //clear the disabled flag
190
    t->state &= ~TASKLET_STATE_DISABLED;
199
    t->state &= ~TASKLET_STATE_DISABLED;
191
    spinlock_unlock(&tasklet_lock);
200
    spinlock_unlock(&tasklet_lock);
192
}
201
}
193
 
202
 
194
 
203
 
195
 
204
 
196
 
205
 
197
/** Executes scheduled enabled tasklets on current CPU */
206
/** Executes scheduled enabled tasklets on current CPU */
198
void tasklet_do(void)
207
void tasklet_do(void)
199
{
208
{
200
    spinlock_lock(&tasklet_lock);
209
    spinlock_lock(&tasklet_lock);
201
    tasklet_descriptor_t* t = tasklet_list[CPU->id];
210
    tasklet_descriptor_t* t = tasklet_list[CPU->id];
202
    //printf(".");
211
    //printf(".");
203
    if (t) {
212
    if (t) {
204
        //empty the tasklet_list
213
        //empty the tasklet_list
205
        tasklet_list[CPU->id]=0;
214
        tasklet_list[CPU->id]=0;
-
 
215
        spinlock_unlock(&tasklet_lock);
206
        do {
216
        do {
207
            if (!(t->state & TASKLET_STATE_DISABLED)) {
217
            if (!(t->state & TASKLET_STATE_DISABLED)) {
208
                if (t->func) {
218
                if (t->func) {
209
                    t->state = TASKLET_STATE_RUNNING;
219
                    t->state = TASKLET_STATE_RUNNING;
210
                    t->func(t->data);
220
                    t->func(t->data);
-
 
221
                    //clear running flag, set not active - the tasklet can disable itself
-
 
222
                    //thats why we don't just set it as not active
-
 
223
                    t->state &= ~TASKLET_STATE_RUNNING;
211
                    t->state = TASKLET_STATE_NOTACTIVE;
224
                    t->state |= TASKLET_STATE_NOTACTIVE;
212
                } else
225
                } else
213
                    panic_printf("tasklet func NULL\n");
226
                    panic_printf("tasklet func NULL\n");
214
            } else {  
227
            } else {  
215
                //return it back to the queue of scheduled tasklets
228
                //return it back to the queue of scheduled tasklets
-
 
229
                spinlock_lock(&tasklet_lock);  
216
                t->next = tasklet_list[CPU->id];
230
                t->next = tasklet_list[CPU->id];
217
                tasklet_list[CPU->id] = t;
231
                tasklet_list[CPU->id] = t;
-
 
232
                spinlock_unlock(&tasklet_lock);
218
            }
233
            }
219
            t=t->next;
234
            t=t->next;
220
        }
235
        }
221
        while (t);
236
        while (t);
222
    }
237
    }
-
 
238
    else
223
    spinlock_unlock(&tasklet_lock);
239
        spinlock_unlock(&tasklet_lock);
224
}
240
}
225
 
241
 
226
/** Frees the tasklet structure when no longer needed. The function doesn't provide
242
/** Frees the tasklet structure when no longer needed. The function doesn't provide
227
*   any synchronization, the caller must be sure, the tasklet is not scheduled.
243
*   any synchronization, the caller must be sure, the tasklet is not scheduled.
228
*
244
*
229
* @param tasklet to be freed
245
* @param tasklet to be freed
230
*/
246
*/
231
void tasklet_free(tasklet_descriptor_t* t)
247
void tasklet_free(tasklet_descriptor_t* t)
232
{
248
{
233
    spinlock_lock(&tasklet_lock);
249
    spinlock_lock(&tasklet_lock);
234
    if (t->state == TASKLET_STATE_NOTACTIVE)
250
    if (t->state == TASKLET_STATE_NOTACTIVE)
235
        free(t);
251
        free(t);
236
    else
252
    else
237
        panic_printf("attempting to free an active tasklet");
253
        panic_printf("attempting to free an active tasklet");
238
    spinlock_unlock(&tasklet_lock);
254
    spinlock_unlock(&tasklet_lock);
239
}
255
}
240
 
256
 
241
 
257
 
242
 
258