Subversion Repositories HelenOS-historic

Rev

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

Rev 11 Rev 15
Line 67... Line 67...
67
    int i, n;
67
    int i, n;
68
 
68
 
69
loop:
69
loop:
70
    cpu_priority_high();
70
    cpu_priority_high();
71
 
71
 
72
    spinlock_lock(&the->cpu->lock);
72
    spinlock_lock(&CPU->lock);
73
    n = the->cpu->nrdy;
73
    n = CPU->nrdy;
74
    spinlock_unlock(&the->cpu->lock);
74
    spinlock_unlock(&CPU->lock);
75
 
75
 
76
    cpu_priority_low();
76
    cpu_priority_low();
77
   
77
   
78
    if (n == 0) {
78
    if (n == 0) {
79
        #ifdef __SMP__
79
        #ifdef __SMP__
80
        /*
80
        /*
81
         * If the load balancing thread is not running, wake it up and
81
         * If the load balancing thread is not running, wake it up and
82
         * set CPU-private flag that the kcpulb has been started.
82
         * set CPU-private flag that the kcpulb has been started.
83
         */
83
         */
84
        if (test_and_set(&the->cpu->kcpulbstarted) == 0) {
84
        if (test_and_set(&CPU->kcpulbstarted) == 0) {
85
                waitq_wakeup(&the->cpu->kcpulb_wq, 0);
85
                waitq_wakeup(&CPU->kcpulb_wq, 0);
86
            goto loop;
86
            goto loop;
87
        }
87
        }
88
        #endif /* __SMP__ */
88
        #endif /* __SMP__ */
89
       
89
       
90
        /*
90
        /*
Line 98... Line 98...
98
    }
98
    }
99
 
99
 
100
    cpu_priority_high();
100
    cpu_priority_high();
101
 
101
 
102
    for (i = 0; i<RQ_COUNT; i++) {
102
    for (i = 0; i<RQ_COUNT; i++) {
103
        r = &the->cpu->rq[i];
103
        r = &CPU->rq[i];
104
        spinlock_lock(&r->lock);
104
        spinlock_lock(&r->lock);
105
        if (r->n == 0) {
105
        if (r->n == 0) {
106
            /*
106
            /*
107
             * If this queue is empty, try a lower-priority queue.
107
             * If this queue is empty, try a lower-priority queue.
108
             */
108
             */
Line 112... Line 112...
112
   
112
   
113
        spinlock_lock(&nrdylock);
113
        spinlock_lock(&nrdylock);
114
        nrdy--;
114
        nrdy--;
115
        spinlock_unlock(&nrdylock);    
115
        spinlock_unlock(&nrdylock);    
116
 
116
 
117
        spinlock_lock(&the->cpu->lock);
117
        spinlock_lock(&CPU->lock);
118
        the->cpu->nrdy--;
118
        CPU->nrdy--;
119
        spinlock_unlock(&the->cpu->lock);
119
        spinlock_unlock(&CPU->lock);
120
 
120
 
121
        r->n--;
121
        r->n--;
122
 
122
 
123
        /*
123
        /*
124
         * Take the first thread from the queue.
124
         * Take the first thread from the queue.
Line 127... Line 127...
127
        list_remove(&t->rq_link);
127
        list_remove(&t->rq_link);
128
 
128
 
129
        spinlock_unlock(&r->lock);
129
        spinlock_unlock(&r->lock);
130
 
130
 
131
        spinlock_lock(&t->lock);
131
        spinlock_lock(&t->lock);
132
        t->cpu = the->cpu;
132
        t->cpu = CPU;
133
 
133
 
134
        t->ticks = us2ticks((i+1)*10000);
134
        t->ticks = us2ticks((i+1)*10000);
135
        t->pri = i; /* eventually correct rq index */
135
        t->pri = i; /* eventually correct rq index */
136
 
136
 
137
        /*
137
        /*
Line 157... Line 157...
157
    link_t head;
157
    link_t head;
158
    runq_t *r;
158
    runq_t *r;
159
    int i, n;
159
    int i, n;
160
 
160
 
161
    list_initialize(&head);
161
    list_initialize(&head);
162
    spinlock_lock(&the->cpu->lock);
162
    spinlock_lock(&CPU->lock);
163
    if (the->cpu->needs_relink > NEEDS_RELINK_MAX) {
163
    if (CPU->needs_relink > NEEDS_RELINK_MAX) {
164
        for (i = start; i<RQ_COUNT-1; i++) {
164
        for (i = start; i<RQ_COUNT-1; i++) {
165
            /* remember and empty rq[i + 1] */
165
            /* remember and empty rq[i + 1] */
166
            r = &the->cpu->rq[i + 1];
166
            r = &CPU->rq[i + 1];
167
            spinlock_lock(&r->lock);
167
            spinlock_lock(&r->lock);
168
            list_concat(&head, &r->rq_head);
168
            list_concat(&head, &r->rq_head);
169
            n = r->n;
169
            n = r->n;
170
            r->n = 0;
170
            r->n = 0;
171
            spinlock_unlock(&r->lock);
171
            spinlock_unlock(&r->lock);
172
       
172
       
173
            /* append rq[i + 1] to rq[i] */
173
            /* append rq[i + 1] to rq[i] */
174
            r = &the->cpu->rq[i];
174
            r = &CPU->rq[i];
175
            spinlock_lock(&r->lock);
175
            spinlock_lock(&r->lock);
176
            list_concat(&r->rq_head, &head);
176
            list_concat(&r->rq_head, &head);
177
            r->n += n;
177
            r->n += n;
178
            spinlock_unlock(&r->lock);
178
            spinlock_unlock(&r->lock);
179
        }
179
        }
180
        the->cpu->needs_relink = 0;
180
        CPU->needs_relink = 0;
181
    }
181
    }
182
    spinlock_unlock(&the->cpu->lock);              
182
    spinlock_unlock(&CPU->lock);               
183
 
183
 
184
}
184
}
185
 
185
 
186
/*
186
/*
187
 * The scheduler.
187
 * The scheduler.
Line 193... Line 193...
193
    pri = cpu_priority_high();
193
    pri = cpu_priority_high();
194
 
194
 
195
    if (haltstate)
195
    if (haltstate)
196
        halt();
196
        halt();
197
 
197
 
198
    if (the->thread) {
198
    if (THREAD) {
199
        spinlock_lock(&the->thread->lock);
199
        spinlock_lock(&THREAD->lock);
200
        if (!context_save(&the->thread->saved_context)) {
200
        if (!context_save(&THREAD->saved_context)) {
201
            /*
201
            /*
202
             * This is the place where threads leave scheduler();
202
             * This is the place where threads leave scheduler();
203
             */
203
             */
204
                spinlock_unlock(&the->thread->lock);
204
                spinlock_unlock(&THREAD->lock);
205
            cpu_priority_restore(the->thread->saved_context.pri);
205
            cpu_priority_restore(THREAD->saved_context.pri);
206
            return;
206
            return;
207
        }
207
        }
208
        the->thread->saved_context.pri = pri;
208
        THREAD->saved_context.pri = pri;
209
    }
209
    }
210
 
210
 
211
    /*
211
    /*
212
     * We may not keep the old stack.
212
     * We may not keep the old stack.
213
     * Reason: If we kept the old stack and got blocked, for instance, in
213
     * Reason: If we kept the old stack and got blocked, for instance, in
Line 218... Line 218...
218
     * Moreover, we have to bypass the compiler-generated POP sequence
218
     * Moreover, we have to bypass the compiler-generated POP sequence
219
     * which is fooled by SP being set to the very top of the stack.
219
     * which is fooled by SP being set to the very top of the stack.
220
     * Therefore the scheduler() function continues in
220
     * Therefore the scheduler() function continues in
221
     * scheduler_separated_stack().
221
     * scheduler_separated_stack().
222
     */
222
     */
223
    context_save(&the->cpu->saved_context);
223
    context_save(&CPU->saved_context);
224
    the->cpu->saved_context.sp = (__address) &the->cpu->stack[CPU_STACK_SIZE-8];
224
    CPU->saved_context.sp = (__address) &CPU->stack[CPU_STACK_SIZE-8];
225
    the->cpu->saved_context.pc = (__address) scheduler_separated_stack;
225
    CPU->saved_context.pc = (__address) scheduler_separated_stack;
226
    context_restore(&the->cpu->saved_context);
226
    context_restore(&CPU->saved_context);
227
    /* not reached */
227
    /* not reached */
228
}
228
}
229
 
229
 
230
void scheduler_separated_stack(void)
230
void scheduler_separated_stack(void)
231
{
231
{
232
    int priority;
232
    int priority;
233
 
233
 
234
    if (the->thread) {
234
    if (THREAD) {
235
        switch (the->thread->state) {
235
        switch (THREAD->state) {
236
            case Running:
236
            case Running:
237
                the->thread->state = Ready;
237
                THREAD->state = Ready;
238
                spinlock_unlock(&the->thread->lock);
238
                spinlock_unlock(&THREAD->lock);
239
                thread_ready(the->thread);
239
                thread_ready(THREAD);
240
                break;
240
                break;
241
 
241
 
242
            case Exiting:
242
            case Exiting:
243
                frame_free((__address) the->thread->kstack);
243
                frame_free((__address) THREAD->kstack);
244
                if (the->thread->ustack) {
244
                if (THREAD->ustack) {
245
                    frame_free((__address) the->thread->ustack);
245
                    frame_free((__address) THREAD->ustack);
246
                }
246
                }
247
               
247
               
248
                /*
248
                /*
249
                 * Detach from the containing task.
249
                 * Detach from the containing task.
250
                 */
250
                 */
251
                spinlock_lock(&the->task->lock);
251
                spinlock_lock(&TASK->lock);
252
                list_remove(&the->thread->th_link);
252
                list_remove(&THREAD->th_link);
253
                spinlock_unlock(&the->task->lock);
253
                spinlock_unlock(&TASK->lock);
254
 
254
 
255
                spinlock_unlock(&the->thread->lock);
255
                spinlock_unlock(&THREAD->lock);
256
               
256
               
257
                spinlock_lock(&threads_lock);
257
                spinlock_lock(&threads_lock);
258
                list_remove(&the->thread->threads_link);
258
                list_remove(&THREAD->threads_link);
259
                spinlock_unlock(&threads_lock);
259
                spinlock_unlock(&threads_lock);
260
               
260
               
261
                free(the->thread);
261
                free(THREAD);
262
               
262
               
263
                break;
263
                break;
264
               
264
               
265
            case Sleeping:
265
            case Sleeping:
266
                /*
266
                /*
267
                 * Prefer the thread after it's woken up.
267
                 * Prefer the thread after it's woken up.
268
                 */
268
                 */
269
                the->thread->pri = -1;
269
                THREAD->pri = -1;
270
 
270
 
271
                /*
271
                /*
272
                 * We need to release wq->lock which we locked in waitq_sleep().
272
                 * We need to release wq->lock which we locked in waitq_sleep().
273
                 * Address of wq->lock is kept in the->thread->sleep_queue.
273
                 * Address of wq->lock is kept in THREAD->sleep_queue.
274
                 */
274
                 */
275
                spinlock_unlock(&the->thread->sleep_queue->lock);
275
                spinlock_unlock(&THREAD->sleep_queue->lock);
276
 
276
 
277
                /*
277
                /*
278
                 * Check for possible requests for out-of-context invocation.
278
                 * Check for possible requests for out-of-context invocation.
279
                 */
279
                 */
280
                if (the->thread->call_me) {
280
                if (THREAD->call_me) {
281
                    the->thread->call_me(the->thread->call_me_with);
281
                    THREAD->call_me(THREAD->call_me_with);
282
                    the->thread->call_me = NULL;
282
                    THREAD->call_me = NULL;
283
                    the->thread->call_me_with = NULL;
283
                    THREAD->call_me_with = NULL;
284
                }
284
                }
285
 
285
 
286
                spinlock_unlock(&the->thread->lock);
286
                spinlock_unlock(&THREAD->lock);
287
               
287
               
288
                break;
288
                break;
289
 
289
 
290
            default:
290
            default:
291
                /*
291
                /*
292
                 * Entering state is unexpected.
292
                 * Entering state is unexpected.
293
                 */
293
                 */
294
                panic("tid%d: unexpected state %s\n", the->thread->tid, thread_states[the->thread->state]);
294
                panic("tid%d: unexpected state %s\n", THREAD->tid, thread_states[THREAD->state]);
295
                break;
295
                break;
296
        }
296
        }
297
        the->thread = NULL;
297
        THREAD = NULL;
298
    }
298
    }
299
   
299
   
300
    the->thread = find_best_thread();
300
    THREAD = find_best_thread();
301
   
301
   
302
    spinlock_lock(&the->thread->lock);
302
    spinlock_lock(&THREAD->lock);
303
    priority = the->thread->pri;
303
    priority = THREAD->pri;
304
    spinlock_unlock(&the->thread->lock);   
304
    spinlock_unlock(&THREAD->lock);
305
   
305
   
306
    relink_rq(priority);       
306
    relink_rq(priority);       
307
 
307
 
308
    spinlock_lock(&the->thread->lock); 
308
    spinlock_lock(&THREAD->lock);  
309
 
309
 
310
    /*
310
    /*
311
     * If both the old and the new task are the same, lots of work is avoided.
311
     * If both the old and the new task are the same, lots of work is avoided.
312
     */
312
     */
313
    if (the->task != the->thread->task) {
313
    if (TASK != THREAD->task) {
314
        vm_t *m1 = NULL;
314
        vm_t *m1 = NULL;
315
        vm_t *m2;
315
        vm_t *m2;
316
 
316
 
317
        if (the->task) {
317
        if (TASK) {
318
            spinlock_lock(&the->task->lock);
318
            spinlock_lock(&TASK->lock);
319
            m1 = the->task->vm;
319
            m1 = TASK->vm;
320
            spinlock_unlock(&the->task->lock);
320
            spinlock_unlock(&TASK->lock);
321
        }
321
        }
322
 
322
 
323
        spinlock_lock(&the->thread->task->lock);
323
        spinlock_lock(&THREAD->task->lock);
324
        m2 = the->thread->task->vm;
324
        m2 = THREAD->task->vm;
325
        spinlock_unlock(&the->thread->task->lock);
325
        spinlock_unlock(&THREAD->task->lock);
326
       
326
       
327
        /*
327
        /*
328
         * Note that it is possible for two tasks to share one vm mapping.
328
         * Note that it is possible for two tasks to share one vm mapping.
329
         */
329
         */
330
        if (m1 != m2) {
330
        if (m1 != m2) {
Line 335... Line 335...
335
            if (m1) {
335
            if (m1) {
336
                vm_uninstall(m1);
336
                vm_uninstall(m1);
337
            }
337
            }
338
            vm_install(m2);
338
            vm_install(m2);
339
        }
339
        }
340
        the->task = the->thread->task; 
340
        TASK = THREAD->task;   
341
    }
341
    }
342
 
342
 
343
    the->thread->state = Running;
343
    THREAD->state = Running;
344
 
344
 
345
    #ifdef SCHEDULER_VERBOSE
345
    #ifdef SCHEDULER_VERBOSE
346
    printf("cpu%d: tid %d (pri=%d,ticks=%d,nrdy=%d)\n", the->cpu->id, the->thread->tid, the->thread->pri, the->thread->ticks, the->cpu->nrdy);
346
    printf("cpu%d: tid %d (pri=%d,ticks=%d,nrdy=%d)\n", CPU->id, THREAD->tid, THREAD->pri, THREAD->ticks, CPU->nrdy);
347
    #endif  
347
    #endif  
348
 
348
 
349
    context_restore(&the->thread->saved_context);
349
    context_restore(&THREAD->saved_context);
350
    /* not reached */
350
    /* not reached */
351
}
351
}
352
 
352
 
353
#ifdef __SMP__
353
#ifdef __SMP__
354
/*
354
/*
Line 363... Line 363...
363
 
363
 
364
loop:
364
loop:
365
    /*
365
    /*
366
     * Sleep until there's some work to do.
366
     * Sleep until there's some work to do.
367
     */
367
     */
368
    waitq_sleep(&the->cpu->kcpulb_wq);
368
    waitq_sleep(&CPU->kcpulb_wq);
369
 
369
 
370
not_satisfied:
370
not_satisfied:
371
    /*
371
    /*
372
     * Calculate the number of threads that will be migrated/stolen from
372
     * Calculate the number of threads that will be migrated/stolen from
373
     * other CPU's. Note that situation can have changed between two
373
     * other CPU's. Note that situation can have changed between two
374
     * passes. Each time get the most up to date counts.
374
     * passes. Each time get the most up to date counts.
375
     */
375
     */
376
    pri = cpu_priority_high();
376
    pri = cpu_priority_high();
377
    spinlock_lock(&the->cpu->lock);
377
    spinlock_lock(&CPU->lock);
378
    count = nrdy / config.cpu_active;
378
    count = nrdy / config.cpu_active;
379
    count -= the->cpu->nrdy;
379
    count -= CPU->nrdy;
380
    spinlock_unlock(&the->cpu->lock);
380
    spinlock_unlock(&CPU->lock);
381
    cpu_priority_restore(pri);
381
    cpu_priority_restore(pri);
382
 
382
 
383
    if (count <= 0)
383
    if (count <= 0)
384
        goto satisfied;
384
        goto satisfied;
385
 
385
 
Line 397... Line 397...
397
 
397
 
398
            /*
398
            /*
399
             * Not interested in ourselves.
399
             * Not interested in ourselves.
400
             * Doesn't require interrupt disabling for kcpulb is X_WIRED.
400
             * Doesn't require interrupt disabling for kcpulb is X_WIRED.
401
             */
401
             */
402
            if (the->cpu == cpu)
402
            if (CPU == cpu)
403
                continue;
403
                continue;
404
 
404
 
405
restart:        pri = cpu_priority_high();
405
restart:        pri = cpu_priority_high();
406
            spinlock_lock(&r->lock);
406
            spinlock_lock(&r->lock);
407
            if (r->n == 0) {
407
            if (r->n == 0) {
Line 458... Line 458...
458
                /*
458
                /*
459
                 * Ready t on local CPU
459
                 * Ready t on local CPU
460
                 */
460
                 */
461
                spinlock_lock(&t->lock);
461
                spinlock_lock(&t->lock);
462
                #ifdef KCPULB_VERBOSE
462
                #ifdef KCPULB_VERBOSE
463
                printf("kcpulb%d: TID %d -> cpu%d, nrdy=%d, avg=%d\n", the->cpu->id, t->tid, the->cpu->id, the->cpu->nrdy, nrdy / config.cpu_active);
463
                printf("kcpulb%d: TID %d -> cpu%d, nrdy=%d, avg=%d\n", CPU->id, t->tid, CPU->id, CPU->nrdy, nrdy / config.cpu_active);
464
                #endif
464
                #endif
465
                t->flags |= X_STOLEN;
465
                t->flags |= X_STOLEN;
466
                spinlock_unlock(&t->lock);
466
                spinlock_unlock(&t->lock);
467
   
467
   
468
                thread_ready(t);
468
                thread_ready(t);
Line 481... Line 481...
481
            }
481
            }
482
            cpu_priority_restore(pri);
482
            cpu_priority_restore(pri);
483
        }
483
        }
484
    }
484
    }
485
 
485
 
486
    if (the->cpu->nrdy) {
486
    if (CPU->nrdy) {
487
        /*
487
        /*
488
         * Be a little bit light-weight and let migrated threads run.
488
         * Be a little bit light-weight and let migrated threads run.
489
         */
489
         */
490
        scheduler();
490
        scheduler();
491
    }
491
    }
Line 501... Line 501...
501
   
501
   
502
satisfied:
502
satisfied:
503
    /*
503
    /*
504
     * Tell find_best_thread() to wake us up later again.
504
     * Tell find_best_thread() to wake us up later again.
505
     */
505
     */
506
    the->cpu->kcpulbstarted = 0;
506
    CPU->kcpulbstarted = 0;
507
    goto loop;
507
    goto loop;
508
}
508
}
509
 
509
 
510
#endif /* __SMP__ */
510
#endif /* __SMP__ */