Subversion Repositories HelenOS

Rev

Rev 2330 | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 2330 Rev 2430
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 tasklet.c
-
 
34
 *  @brief Tasklet implementation
34
 */
35
 */
35
 
36
 
36
#include <arch.h>
37
#include <arch.h>
37
#include <config.h>
38
#include <config.h>
38
#include <arch/types.h>
39
#include <arch/types.h>
39
#include <arch/asm.h>
40
#include <arch/asm.h>
40
#include <proc/tasklet.h>
41
#include <proc/tasklet.h>
41
#include <synch/spinlock.h>
42
#include <synch/spinlock.h>
42
#include <time/delay.h>
43
#include <time/delay.h>
43
#include <proc/thread.h>
44
#include <proc/thread.h>
44
#include <panic.h>
45
#include <panic.h>
45
#include <print.h>
46
#include <print.h>
46
#include <synch/waitq.h>
47
#include <synch/waitq.h>
47
#include <cpu.h>
48
#include <cpu.h>
48
#include <proc/scheduler.h>
49
#include <proc/scheduler.h>
49
 
50
 
50
/** Timeout length in the tasklet thread */
51
/** Timeout length in the tasklet thread */
51
#define TASKLET_THREAD_SLEEPDELAY 10000
52
#define TASKLET_THREAD_SLEEPDELAY 10000
52
///** Priority of the tasklet thread */
53
///** Priority of the tasklet thread */
53
#define TASKLET_THREAD_PRIORITY 1
54
#define TASKLET_THREAD_PRIORITY 1
54
 
55
 
55
 
56
 
56
/** Tasklet state enum */
57
/** Tasklet state enum */
57
typedef enum  {
58
typedef enum  {
58
TASKLET_STATE_NOTACTIVE = 0,
59
TASKLET_STATE_NOTACTIVE = 0,
59
TASKLET_STATE_SCHEDULED = 1,
60
TASKLET_STATE_SCHEDULED = 1,
60
TASKLET_STATE_RUNNING = 2,
61
TASKLET_STATE_RUNNING = 2,
61
TASKLET_STATE_DISABLED = 4
62
TASKLET_STATE_DISABLED = 4
62
} tasklet_state_enum;
63
} tasklet_state_enum;
63
 
64
 
64
/** Spinlock protecting list of tasklets */
65
/** Spinlock protecting list of tasklets */
65
SPINLOCK_INITIALIZE(tasklet_lock);
66
SPINLOCK_INITIALIZE(tasklet_lock);
66
 
67
 
67
/** array of tasklet lists for every CPU */
68
/** array of tasklet lists for every CPU */
68
tasklet_descriptor_t** tasklet_list;
69
tasklet_descriptor_t** tasklet_list;
69
 
70
 
70
/** Initializes tasklets - except for the tasklet thread */
71
/** Initializes tasklets - except for the tasklet thread */
71
void tasklet_init(void)
72
void tasklet_init(void)
72
{
73
{
73
    int i;
74
    int i;
74
    tasklet_list=malloc(sizeof(tasklet_descriptor_t*)*config.cpu_count,0);
75
    tasklet_list=malloc(sizeof(tasklet_descriptor_t*)*config.cpu_count,0);
75
    if (tasklet_list==0)
76
    if (tasklet_list==0)
76
        panic_printf("tasklet list mem not allocated\n");
77
        panic_printf("tasklet list mem not allocated\n");
77
    for(i=0;i<config.cpu_count;i++) {
78
    for(i=0;i<config.cpu_count;i++) {
78
        tasklet_list[i]=0;
79
        tasklet_list[i]=0;
79
    }
80
    }
80
    spinlock_initialize(&tasklet_lock, "tasklet_lock");
81
    spinlock_initialize(&tasklet_lock, "tasklet_lock");
81
 
82
 
82
}
83
}
83
 
84
 
84
/**
85
/**
85
* Creates and runs the tasklet thread
86
* Creates and runs the tasklet thread
86
*
87
*
87
*  @param kernel_task Pointer to the kernel task - for create_thread
88
*  @param kernel_task Pointer to the kernel task - for create_thread
88
*/
89
*/
89
void tasklet_run_tasklet_thread(task_t * kernel_task)
90
void tasklet_run_tasklet_thread(task_t * kernel_task)
90
{
91
{
91
    //create the tasklet_thread, it's wired to the current cpu, we'll migrate it ourselves
92
    //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);
93
    thread_t* t= thread_create(&tasklet_thread, NULL, kernel_task, THREAD_FLAG_WIRED, "tasklet_thread", false);
93
    if (t==NULL) {
94
    if (t==NULL) {
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
        //we'll default on the first CPU
98
        t->cpu = &cpus[0];
99
        t->cpu = &cpus[0];
99
        t->priority = TASKLET_THREAD_PRIORITY;
100
        t->priority = TASKLET_THREAD_PRIORITY;
100
        spinlock_unlock(&t->lock);
101
        spinlock_unlock(&t->lock);
101
        thread_ready(t);
102
        thread_ready(t);
102
    }
103
    }
103
}
104
}
104
 
105
 
105
/** Thread which keeps executing scheduled enabled tasklets
106
/** Thread which keeps executing scheduled enabled tasklets
106
* @param data not used
107
* @param data not used
107
*/
108
*/
108
void tasklet_thread(void* data)
109
void tasklet_thread(void* data)
109
{
110
{
110
#ifdef CONFIG_SMP
111
#ifdef CONFIG_SMP
111
    int current_cpu, new_cpu ;
112
    int current_cpu, new_cpu ;
112
    cpu_t *cpu;
113
    cpu_t *cpu;
113
#endif
114
#endif
114
    waitq_t  wq;
115
    waitq_t  wq;
115
    waitq_initialize(&wq);
116
    waitq_initialize(&wq);
116
   
117
   
-
 
118
    //the infinite loop
117
    while (true) {
119
    while (true) {
-
 
120
        //execute any scheduled tasklets
118
        tasklet_do();
121
        tasklet_do();
119
#ifdef CONFIG_SMP
122
#ifdef CONFIG_SMP
-
 
123
        //check whether other CPUs have tasklets to execute
120
        if (config.cpu_active>1) {
124
        if (config.cpu_active>1) {
121
            current_cpu = CPU->id;
125
            current_cpu = CPU->id;
122
            //find the first cpu with nonempty tasklet_list 
126
            //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 && cpus[new_cpu].active;
127
            for (new_cpu = (current_cpu + 1) % config.cpu_count; new_cpu!=current_cpu && tasklet_list[new_cpu]==0 ;
124
                    new_cpu=(new_cpu + 1)% config.cpu_active);
128
                    new_cpu=(new_cpu + 1)% config.cpu_count);
125
 
129
 
-
 
130
            //if we found a CPU with unsatisfied tasklet schedule to run there. It must be active!
126
            if (new_cpu!=current_cpu) {
131
            if (new_cpu!=current_cpu && cpus[new_cpu].active) {
127
                //we need to migrate this thread to CPU with id new_cpu
132
                //we need to migrate this thread to CPU with id new_cpu
128
                cpu = &cpus[new_cpu];
133
                cpu = &cpus[new_cpu];
129
 
134
 
130
                spinlock_lock(&THREAD->lock);
135
                spinlock_lock(&THREAD->lock);
131
                //put tasklet_thread on the new_cpu 
136
                //move tasklet_thread on the new_cpu 
132
                THREAD->cpu = cpu;
137
                THREAD->cpu = cpu;
133
                spinlock_unlock(&THREAD->lock);
138
                spinlock_unlock(&THREAD->lock);
134
            }
139
            }
135
        }
140
        }
136
#endif
141
#endif
137
        waitq_sleep_timeout(&wq, (uint32_t)TASKLET_THREAD_SLEEPDELAY, 0);
142
        waitq_sleep_timeout(&wq, (uint32_t)TASKLET_THREAD_SLEEPDELAY, 0);
138
 
143
 
139
 
144
 
140
    }
145
    }
141
}
146
}
142
 
147
 
143
/** Initializes tasklet structure
148
/** Initializes tasklet structure
144
* @param func tasklet callback function to be called
149
* @param func tasklet callback function to be called
145
* @param data pointer to be passed to the tasklet function
150
* @param data pointer to be passed to the tasklet function
146
*/
151
*/
147
tasklet_descriptor_t* tasklet_register(void (*func)(void* data), void* data)
152
tasklet_descriptor_t* tasklet_register(void (*func)(void* data), void* data)
148
{
153
{
149
    tasklet_descriptor_t* tasklet=malloc(sizeof(tasklet_descriptor_t),0);
154
    tasklet_descriptor_t* tasklet=malloc(sizeof(tasklet_descriptor_t),0);
150
    tasklet->data = data;
155
    tasklet->data = data;
151
    tasklet->func = func;
156
    tasklet->func = func;
152
    tasklet->state = TASKLET_STATE_NOTACTIVE;
157
    tasklet->state = TASKLET_STATE_NOTACTIVE;
153
    tasklet->next = 0;
158
    tasklet->next = 0;
154
    return tasklet;
159
    return tasklet;
155
}
160
}
156
 
161
 
157
/** Schedules the tasklet for execution on current CPU
162
/** Schedules the tasklet for execution on current CPU
158
* @param t tasklet to be scheduled
163
* @param t tasklet to be scheduled
159
*/
164
*/
160
void tasklet_schedule(tasklet_descriptor_t* t)
165
void tasklet_schedule(tasklet_descriptor_t* t)
161
{
166
{
162
    tasklet_schedule_SMP(t, CPU->id);
167
    tasklet_schedule_SMP(t, CPU->id);
163
}
168
}
164
 
169
 
165
/** Schedules the tasklet for execution on id CPU
170
/** Schedules the tasklet for execution on id CPU
166
* @param t tasklet to be scheduled
171
* @param t tasklet to be scheduled
167
* @param id CPU id on which the tasklet will be scheduled
172
* @param id CPU id on which the tasklet will be scheduled
168
*/
173
*/
169
void tasklet_schedule_SMP(tasklet_descriptor_t* t, uint32_t id)
174
void tasklet_schedule_SMP(tasklet_descriptor_t* t, uint32_t id)
170
{
175
{
171
    spinlock_lock(&tasklet_lock);
176
    spinlock_lock(&tasklet_lock);
172
    //clear notactive, running and scheduled flags
177
    //clear notactive, running and scheduled flags
173
    t->state &= TASKLET_STATE_DISABLED;
178
    t->state &= TASKLET_STATE_DISABLED;
174
    //set the scheduled flag
179
    //set the scheduled flag
175
    t->state |= TASKLET_STATE_SCHEDULED;
180
    t->state |= TASKLET_STATE_SCHEDULED;
176
    t->next=tasklet_list[id];
181
    t->next=tasklet_list[id];
177
    tasklet_list[id]=t;
182
    tasklet_list[id]=t;
178
    spinlock_unlock(&tasklet_lock);
183
    spinlock_unlock(&tasklet_lock);
179
}
184
}
180
 
185
 
181
/** Tasklet will not be run, even if scheduled
186
/** Tasklet will not be run, even if scheduled
182
* @param t tasklet to be disabled
187
* @param t tasklet to be disabled
183
*/
188
*/
184
void tasklet_disable(tasklet_descriptor_t* t)
189
void tasklet_disable(tasklet_descriptor_t* t)
185
{
190
{
186
    spinlock_lock(&tasklet_lock);
191
    spinlock_lock(&tasklet_lock);
187
    //set the disabled flag
192
    //set the disabled flag
188
    t->state |= TASKLET_STATE_DISABLED;
193
    t->state |= TASKLET_STATE_DISABLED;
189
    spinlock_unlock(&tasklet_lock);
194
    spinlock_unlock(&tasklet_lock);
190
}
195
}
191
 
196
 
192
/** Tasklet will be run if scheduled
197
/** Tasklet will be run if scheduled
193
* @param t tasklet to be enabled
198
* @param t tasklet to be enabled
194
*/
199
*/
195
void tasklet_enable(tasklet_descriptor_t* t)
200
void tasklet_enable(tasklet_descriptor_t* t)
196
{
201
{
197
    spinlock_lock(&tasklet_lock);
202
    spinlock_lock(&tasklet_lock);
198
    //clear the disabled flag
203
    //clear the disabled flag
199
    t->state &= ~TASKLET_STATE_DISABLED;
204
    t->state &= ~TASKLET_STATE_DISABLED;
200
    spinlock_unlock(&tasklet_lock);
205
    spinlock_unlock(&tasklet_lock);
201
}
206
}
202
 
207
 
203
 
208
 
204
 
209
 
205
 
210
 
206
/** Executes scheduled enabled tasklets on current CPU */
211
/** Executes scheduled enabled tasklets on current CPU
-
 
212
* this function could be called from other parts of kernel */
207
void tasklet_do(void)
213
void tasklet_do(void)
208
{
214
{
209
    spinlock_lock(&tasklet_lock);
215
    spinlock_lock(&tasklet_lock);
210
    tasklet_descriptor_t* t = tasklet_list[CPU->id];
216
    tasklet_descriptor_t* t = tasklet_list[CPU->id];
211
    //printf(".");
-
 
212
    if (t) {
217
    if (t) {
213
        //empty the tasklet_list
218
        //empty the tasklet_list
214
        tasklet_list[CPU->id]=0;
219
        tasklet_list[CPU->id]=0;
215
        spinlock_unlock(&tasklet_lock);
220
        spinlock_unlock(&tasklet_lock);
216
        do {
221
        do {
217
            if (!(t->state & TASKLET_STATE_DISABLED)) {
222
            if (!(t->state & TASKLET_STATE_DISABLED)) {
218
                if (t->func) {
223
                if (t->func) {
219
                    t->state = TASKLET_STATE_RUNNING;
224
                    t->state = TASKLET_STATE_RUNNING;
220
                    t->func(t->data);
225
                    t->func(t->data);
221
                    //clear running flag, set not active - the tasklet can disable itself
226
                    //clear running flag, set not active 
222
                    //thats why we don't just set it as not active
-
 
223
                    t->state &= ~TASKLET_STATE_RUNNING;
227
                    t->state &= ~TASKLET_STATE_RUNNING;
224
                    t->state |= TASKLET_STATE_NOTACTIVE;
228
                    t->state |= TASKLET_STATE_NOTACTIVE;
225
                } else
229
                } else
226
                    panic_printf("tasklet func NULL\n");
230
                    panic_printf("tasklet func NULL\n");
227
            } else {  
231
            } else {  
228
                //return it back to the queue of scheduled tasklets
232
                //return it back to the queue of scheduled tasklets
229
                spinlock_lock(&tasklet_lock);  
233
                spinlock_lock(&tasklet_lock);  
230
                t->next = tasklet_list[CPU->id];
234
                t->next = tasklet_list[CPU->id];
231
                tasklet_list[CPU->id] = t;
235
                tasklet_list[CPU->id] = t;
232
                spinlock_unlock(&tasklet_lock);
236
                spinlock_unlock(&tasklet_lock);
233
            }
237
            }
234
            t=t->next;
238
            t=t->next;
235
        }
239
        }
236
        while (t);
240
        while (t);
237
    }
241
    }
238
    else
242
    else
239
        spinlock_unlock(&tasklet_lock);
243
        spinlock_unlock(&tasklet_lock);
240
}
244
}
241
 
245
 
242
/** Frees the tasklet structure when no longer needed. The function doesn't provide
246
/** Frees the tasklet structure when no longer needed. The function doesn't provide
243
*   any synchronization, the caller must be sure, the tasklet is not scheduled.
247
*   any synchronization, the caller must be sure, that the tasklet is not scheduled.
244
*
248
*
245
* @param tasklet to be freed
249
* @param tasklet to be freed
246
*/
250
*/
247
void tasklet_free(tasklet_descriptor_t* t)
251
void tasklet_free(tasklet_descriptor_t* t)
248
{
252
{
249
    spinlock_lock(&tasklet_lock);
253
    spinlock_lock(&tasklet_lock);
250
    if (t->state == TASKLET_STATE_NOTACTIVE)
254
    if (t->state == TASKLET_STATE_NOTACTIVE)
251
        free(t);
255
        free(t);
252
    else
256
    else
253
        panic_printf("attempting to free an active tasklet");
257
        panic_printf("attempting to free an active tasklet");
254
    spinlock_unlock(&tasklet_lock);
258
    spinlock_unlock(&tasklet_lock);
255
}
259
}
256
 
260
 
257
 
261
 
258
 
262