00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039 #include <minix/com.h>
00040 #include <minix/callnr.h>
00041 #include <minix/endpoint.h>
00042 #include "debug.h"
00043 #include "kernel.h"
00044 #include "proc.h"
00045 #include <signal.h>
00046
00047
00048
00049
00050
00051 FORWARD _PROTOTYPE( int mini_send, (struct proc *caller_ptr, int dst_e,
00052 message *m_ptr, unsigned flags));
00053 FORWARD _PROTOTYPE( int mini_receive, (struct proc *caller_ptr, int src,
00054 message *m_ptr, unsigned flags));
00055 FORWARD _PROTOTYPE( int mini_notify, (struct proc *caller_ptr, int dst));
00056 FORWARD _PROTOTYPE( int deadlock, (int function,
00057 register struct proc *caller, int src_dst));
00058 FORWARD _PROTOTYPE( void enqueue, (struct proc *rp));
00059 FORWARD _PROTOTYPE( void dequeue, (struct proc *rp));
00060 FORWARD _PROTOTYPE( void sched, (struct proc *rp, int *queue, int *front));
00061 FORWARD _PROTOTYPE( void pick_proc, (void));
00062
00063 #define BuildMess(m_ptr, src, dst_ptr) \
00064 (m_ptr)->m_source = proc_addr(src)->p_endpoint; \
00065 (m_ptr)->m_type = NOTIFY_FROM(src); \
00066 (m_ptr)->NOTIFY_TIMESTAMP = get_uptime(); \
00067 switch (src) { \
00068 case HARDWARE: \
00069 (m_ptr)->NOTIFY_ARG = priv(dst_ptr)->s_int_pending; \
00070 priv(dst_ptr)->s_int_pending = 0; \
00071 break; \
00072 case SYSTEM: \
00073 (m_ptr)->NOTIFY_ARG = priv(dst_ptr)->s_sig_pending; \
00074 priv(dst_ptr)->s_sig_pending = 0; \
00075 break; \
00076 }
00077
00078 #if (CHIP == INTEL)
00079 #define CopyMess(s,sp,sm,dp,dm) \
00080 cp_mess(proc_addr(s)->p_endpoint, \
00081 (sp)->p_memmap[D].mem_phys, \
00082 (vir_bytes)sm, (dp)->p_memmap[D].mem_phys, (vir_bytes)dm)
00083 #endif
00084
00085 #if (CHIP == M68000)
00086
00087
00088
00089 #endif
00090
00091
00092
00093
00094 PUBLIC int sys_call(call_nr, src_dst_e, m_ptr, bit_map)
00095 int call_nr;
00096 int src_dst_e;
00097 message *m_ptr;
00098 long bit_map;
00099 {
00100
00101
00102
00103
00104 register struct proc *caller_ptr = proc_ptr;
00105 int function = call_nr & SYSCALL_FUNC;
00106 unsigned flags = call_nr & SYSCALL_FLAGS;
00107 int mask_entry;
00108 int group_size;
00109 int result;
00110 int src_dst;
00111 vir_clicks vlo, vhi;
00112
00113 #if 0
00114 if (caller_ptr->p_rts_flags & SLOT_FREE)
00115 {
00116 kprintf("called by the dead?!?\n");
00117 return EINVAL;
00118 }
00119 #endif
00120
00121
00122 if (src_dst_e != ANY && function != ECHO) {
00123 if(!isokendpt(src_dst_e, &src_dst)) {
00124 #if DEBUG_ENABLE_IPC_WARNINGS
00125 kprintf("sys_call: trap %d by %d with bad endpoint %d\n",
00126 function, proc_nr(caller_ptr), src_dst_e);
00127 #endif
00128 return EDEADSRCDST;
00129 }
00130 } else src_dst = src_dst_e;
00131
00132
00133
00134
00135
00136 if (! (priv(caller_ptr)->s_trap_mask & (1 << function)) ||
00137 (iskerneln(src_dst) && function != SENDREC
00138 && function != RECEIVE)) {
00139 #if DEBUG_ENABLE_IPC_WARNINGS
00140 kprintf("sys_call: trap %d not allowed, caller %d, src_dst %d\n",
00141 function, proc_nr(caller_ptr), src_dst);
00142 #endif
00143 return(ETRAPDENIED);
00144 }
00145
00146
00147
00148
00149
00150
00151 if (function & CHECK_PTR) {
00152 vlo = (vir_bytes) m_ptr >> CLICK_SHIFT;
00153 vhi = ((vir_bytes) m_ptr + MESS_SIZE - 1) >> CLICK_SHIFT;
00154 if (vlo < caller_ptr->p_memmap[D].mem_vir || vlo > vhi ||
00155 vhi >= caller_ptr->p_memmap[S].mem_vir +
00156 caller_ptr->p_memmap[S].mem_len) {
00157 #if DEBUG_ENABLE_IPC_WARNINGS
00158 kprintf("sys_call: invalid message pointer, trap %d, caller %d\n",
00159 function, proc_nr(caller_ptr));
00160 #endif
00161 return(EFAULT);
00162 }
00163 }
00164
00165
00166
00167
00168 if (function & CHECK_DST) {
00169 if (! get_sys_bit(priv(caller_ptr)->s_ipc_to, nr_to_id(src_dst))) {
00170 #if DEBUG_ENABLE_IPC_WARNINGS
00171 kprintf("sys_call: ipc mask denied trap %d from %d to %d\n",
00172 function, proc_nr(caller_ptr), src_dst);
00173 #endif
00174 return(ECALLDENIED);
00175 }
00176 }
00177
00178
00179 if (function & CHECK_DEADLOCK) {
00180 if (group_size = deadlock(function, caller_ptr, src_dst)) {
00181 #if DEBUG_ENABLE_IPC_WARNINGS
00182 kprintf("sys_call: trap %d from %d to %d deadlocked, group size %d\n",
00183 function, proc_nr(caller_ptr), src_dst, group_size);
00184 #endif
00185 return(ELOCKED);
00186 }
00187 }
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197 switch(function) {
00198 case SENDREC:
00199
00200 caller_ptr->p_misc_flags |= REPLY_PENDING;
00201
00202 case SEND:
00203 result = mini_send(caller_ptr, src_dst_e, m_ptr, flags);
00204 if (function == SEND || result != OK) {
00205 break;
00206 }
00207 case RECEIVE:
00208 if (function == RECEIVE)
00209 caller_ptr->p_misc_flags &= ~REPLY_PENDING;
00210 result = mini_receive(caller_ptr, src_dst_e, m_ptr, flags);
00211 break;
00212 case NOTIFY:
00213 result = mini_notify(caller_ptr, src_dst);
00214 break;
00215 case ECHO:
00216 CopyMess(caller_ptr->p_nr, caller_ptr, m_ptr, caller_ptr, m_ptr);
00217 result = OK;
00218 break;
00219 default:
00220 result = EBADCALL;
00221 }
00222
00223
00224 return(result);
00225 }
00226
00227
00228
00229
00230 PRIVATE int deadlock(function, cp, src_dst)
00231 int function;
00232 register struct proc *cp;
00233 int src_dst;
00234 {
00235
00236
00237
00238
00239
00240
00241 register struct proc *xp;
00242 int group_size = 1;
00243 int trap_flags;
00244
00245 while (src_dst != ANY) {
00246 int src_dst_e;
00247 xp = proc_addr(src_dst);
00248 group_size ++;
00249
00250
00251
00252
00253 if (xp->p_rts_flags & RECEIVING) {
00254 if(xp->p_getfrom_e == ANY) src_dst = ANY;
00255 else okendpt(xp->p_getfrom_e, &src_dst);
00256 } else if (xp->p_rts_flags & SENDING) {
00257 okendpt(xp->p_sendto_e, &src_dst);
00258 } else {
00259 return(0);
00260 }
00261
00262
00263
00264
00265
00266 if (src_dst == proc_nr(cp)) {
00267 if (group_size == 2) {
00268
00269 if ((xp->p_rts_flags ^ (function << 2)) & SENDING) {
00270 return(0);
00271 }
00272 }
00273 return(group_size);
00274 }
00275 }
00276 return(0);
00277 }
00278
00279
00280
00281
00282 PRIVATE int mini_send(caller_ptr, dst_e, m_ptr, flags)
00283 register struct proc *caller_ptr;
00284 int dst_e;
00285 message *m_ptr;
00286 unsigned flags;
00287 {
00288
00289
00290
00291
00292 register struct proc *dst_ptr;
00293 register struct proc **xpp;
00294 int dst_p;
00295
00296 dst_p = _ENDPOINT_P(dst_e);
00297 dst_ptr = proc_addr(dst_p);
00298
00299 if (dst_ptr->p_rts_flags & NO_ENDPOINT) return EDSTDIED;
00300
00301
00302
00303
00304 if ( (dst_ptr->p_rts_flags & (RECEIVING | SENDING)) == RECEIVING &&
00305 (dst_ptr->p_getfrom_e == ANY
00306 || dst_ptr->p_getfrom_e == caller_ptr->p_endpoint)) {
00307
00308 CopyMess(caller_ptr->p_nr, caller_ptr, m_ptr, dst_ptr,
00309 dst_ptr->p_messbuf);
00310 if ((dst_ptr->p_rts_flags &= ~RECEIVING) == 0) enqueue(dst_ptr);
00311 } else if ( ! (flags & NON_BLOCKING)) {
00312
00313 caller_ptr->p_messbuf = m_ptr;
00314 if (caller_ptr->p_rts_flags == 0) dequeue(caller_ptr);
00315 caller_ptr->p_rts_flags |= SENDING;
00316 caller_ptr->p_sendto_e = dst_e;
00317
00318
00319 xpp = &dst_ptr->p_caller_q;
00320 while (*xpp != NIL_PROC) xpp = &(*xpp)->p_q_link;
00321 *xpp = caller_ptr;
00322 caller_ptr->p_q_link = NIL_PROC;
00323 } else {
00324 return(ENOTREADY);
00325 }
00326 return(OK);
00327 }
00328
00329
00330
00331
00332 PRIVATE int mini_receive(caller_ptr, src_e, m_ptr, flags)
00333 register struct proc *caller_ptr;
00334 int src_e;
00335 message *m_ptr;
00336 unsigned flags;
00337 {
00338
00339
00340
00341
00342 register struct proc **xpp;
00343 register struct notification **ntf_q_pp;
00344 message m;
00345 int bit_nr;
00346 sys_map_t *map;
00347 bitchunk_t *chunk;
00348 int i, src_id, src_proc_nr, src_p;
00349
00350 if(src_e == ANY) src_p = ANY;
00351 else
00352 {
00353 okendpt(src_e, &src_p);
00354 if (proc_addr(src_p)->p_rts_flags & NO_ENDPOINT) return ESRCDIED;
00355 }
00356
00357
00358
00359
00360
00361
00362 if (!(caller_ptr->p_rts_flags & SENDING)) {
00363
00364
00365 if (! (caller_ptr->p_misc_flags & REPLY_PENDING)) {
00366
00367 map = &priv(caller_ptr)->s_notify_pending;
00368 for (chunk=&map->chunk[0]; chunk<&map->chunk[NR_SYS_CHUNKS]; chunk++) {
00369
00370
00371 if (! *chunk) continue;
00372 for (i=0; ! (*chunk & (1<<i)); ++i) {}
00373 src_id = (chunk - &map->chunk[0]) * BITCHUNK_BITS + i;
00374 if (src_id >= NR_SYS_PROCS) break;
00375 src_proc_nr = id_to_nr(src_id);
00376 #if DEBUG_ENABLE_IPC_WARNINGS
00377 if(src_proc_nr == NONE) {
00378 kprintf("mini_receive: sending notify from NONE\n");
00379 }
00380 #endif
00381 if (src_e!=ANY && src_p != src_proc_nr) continue;
00382 *chunk &= ~(1 << i);
00383
00384
00385 BuildMess(&m, src_proc_nr, caller_ptr);
00386 CopyMess(src_proc_nr, proc_addr(HARDWARE), &m, caller_ptr, m_ptr);
00387 return(OK);
00388 }
00389 }
00390
00391
00392 xpp = &caller_ptr->p_caller_q;
00393 while (*xpp != NIL_PROC) {
00394 if (src_e == ANY || src_p == proc_nr(*xpp)) {
00395 #if 0
00396 if ((*xpp)->p_rts_flags & SLOT_FREE)
00397 {
00398 kprintf("listening to the dead?!?\n");
00399 return EINVAL;
00400 }
00401 #endif
00402
00403
00404 CopyMess((*xpp)->p_nr, *xpp, (*xpp)->p_messbuf, caller_ptr, m_ptr);
00405 if (((*xpp)->p_rts_flags &= ~SENDING) == 0) enqueue(*xpp);
00406 *xpp = (*xpp)->p_q_link;
00407 return(OK);
00408 }
00409 xpp = &(*xpp)->p_q_link;
00410 }
00411 }
00412
00413
00414
00415
00416 if ( ! (flags & NON_BLOCKING)) {
00417 caller_ptr->p_getfrom_e = src_e;
00418 caller_ptr->p_messbuf = m_ptr;
00419 if (caller_ptr->p_rts_flags == 0) dequeue(caller_ptr);
00420 caller_ptr->p_rts_flags |= RECEIVING;
00421 return(OK);
00422 } else {
00423 return(ENOTREADY);
00424 }
00425 }
00426
00427
00428
00429
00430 PRIVATE int mini_notify(caller_ptr, dst)
00431 register struct proc *caller_ptr;
00432 int dst;
00433 {
00434 register struct proc *dst_ptr = proc_addr(dst);
00435 int src_id;
00436 message m;
00437
00438
00439
00440
00441 if ((dst_ptr->p_rts_flags & (RECEIVING|SENDING)) == RECEIVING &&
00442 ! (dst_ptr->p_misc_flags & REPLY_PENDING) &&
00443 (dst_ptr->p_getfrom_e == ANY ||
00444 dst_ptr->p_getfrom_e == caller_ptr->p_endpoint)) {
00445
00446
00447
00448
00449
00450 BuildMess(&m, proc_nr(caller_ptr), dst_ptr);
00451 CopyMess(proc_nr(caller_ptr), proc_addr(HARDWARE), &m,
00452 dst_ptr, dst_ptr->p_messbuf);
00453 dst_ptr->p_rts_flags &= ~RECEIVING;
00454 if (dst_ptr->p_rts_flags == 0) enqueue(dst_ptr);
00455 return(OK);
00456 }
00457
00458
00459
00460
00461
00462 src_id = priv(caller_ptr)->s_id;
00463 set_sys_bit(priv(dst_ptr)->s_notify_pending, src_id);
00464 return(OK);
00465 }
00466
00467
00468
00469
00470 PUBLIC int lock_notify(src_e, dst_e)
00471 int src_e;
00472 int dst_e;
00473 {
00474
00475
00476
00477
00478
00479
00480 int result, src, dst;
00481
00482 if(!isokendpt(src_e, &src) || !isokendpt(dst_e, &dst))
00483 return EDEADSRCDST;
00484
00485
00486 if (k_reenter >= 0) {
00487 result = mini_notify(proc_addr(src), dst);
00488 }
00489
00490
00491 else {
00492 lock(0, "notify");
00493 result = mini_notify(proc_addr(src), dst);
00494 unlock(0);
00495 }
00496 return(result);
00497 }
00498
00499
00500
00501
00502 PRIVATE void enqueue(rp)
00503 register struct proc *rp;
00504 {
00505
00506
00507
00508
00509
00510 int q;
00511 int front;
00512
00513 #if DEBUG_SCHED_CHECK
00514 check_runqueues("enqueue");
00515 if (rp->p_ready) kprintf("enqueue() already ready process\n");
00516 #endif
00517
00518
00519 sched(rp, &q, &front);
00520
00521
00522 if (rdy_head[q] == NIL_PROC) {
00523 rdy_head[q] = rdy_tail[q] = rp;
00524 rp->p_nextready = NIL_PROC;
00525 }
00526 else if (front) {
00527 rp->p_nextready = rdy_head[q];
00528 rdy_head[q] = rp;
00529 }
00530 else {
00531 rdy_tail[q]->p_nextready = rp;
00532 rdy_tail[q] = rp;
00533 rp->p_nextready = NIL_PROC;
00534 }
00535
00536
00537 pick_proc();
00538
00539 #if DEBUG_SCHED_CHECK
00540 rp->p_ready = 1;
00541 check_runqueues("enqueue");
00542 #endif
00543 }
00544
00545
00546
00547
00548 PRIVATE void dequeue(rp)
00549 register struct proc *rp;
00550 {
00551
00552
00553
00554
00555 register int q = rp->p_priority;
00556 register struct proc **xpp;
00557 register struct proc *prev_xp;
00558
00559
00560 if (iskernelp(rp)) {
00561 if (*priv(rp)->s_stack_guard != STACK_GUARD)
00562 panic("stack overrun by task", proc_nr(rp));
00563 }
00564
00565 #if DEBUG_SCHED_CHECK
00566 check_runqueues("dequeue");
00567 if (! rp->p_ready) kprintf("dequeue() already unready process\n");
00568 #endif
00569
00570
00571
00572
00573
00574 prev_xp = NIL_PROC;
00575 for (xpp = &rdy_head[q]; *xpp != NIL_PROC; xpp = &(*xpp)->p_nextready) {
00576
00577 if (*xpp == rp) {
00578 *xpp = (*xpp)->p_nextready;
00579 if (rp == rdy_tail[q])
00580 rdy_tail[q] = prev_xp;
00581 if (rp == proc_ptr || rp == next_ptr)
00582 pick_proc();
00583 break;
00584 }
00585 prev_xp = *xpp;
00586 }
00587
00588 #if DEBUG_SCHED_CHECK
00589 rp->p_ready = 0;
00590 check_runqueues("dequeue");
00591 #endif
00592 }
00593
00594
00595
00596
00597 PRIVATE void sched(rp, queue, front)
00598 register struct proc *rp;
00599 int *queue;
00600 int *front;
00601 {
00602
00603
00604
00605
00606 int time_left = (rp->p_ticks_left > 0);
00607
00608
00609
00610
00611
00612 if (! time_left) {
00613 rp->p_ticks_left = rp->p_quantum_size;
00614 if (rp->p_priority < (IDLE_Q-1)) {
00615 rp->p_priority += 1;
00616 }
00617 }
00618
00619
00620
00621
00622
00623 *queue = rp->p_priority;
00624 *front = time_left;
00625 }
00626
00627
00628
00629
00630 PRIVATE void pick_proc()
00631 {
00632
00633
00634
00635
00636 register struct proc *rp;
00637 int q;
00638
00639
00640
00641
00642
00643 for (q=0; q < NR_SCHED_QUEUES; q++) {
00644 if ( (rp = rdy_head[q]) != NIL_PROC) {
00645 next_ptr = rp;
00646 if (priv(rp)->s_flags & BILLABLE)
00647 bill_ptr = rp;
00648 return;
00649 }
00650 }
00651 }
00652
00653
00654
00655
00656 #define Q_BALANCE_TICKS 100
00657 PUBLIC void balance_queues(tp)
00658 timer_t *tp;
00659 {
00660
00661
00662
00663
00664 static timer_t queue_timer;
00665 register struct proc* rp;
00666 clock_t next_period;
00667 int ticks_added = 0;
00668
00669 for (rp=BEG_PROC_ADDR; rp<END_PROC_ADDR; rp++) {
00670 if (! isemptyp(rp)) {
00671 lock(5,"balance_queues");
00672 if (rp->p_priority > rp->p_max_priority) {
00673 if (rp->p_rts_flags == 0) dequeue(rp);
00674 ticks_added += rp->p_quantum_size;
00675 rp->p_priority -= 1;
00676 if (rp->p_rts_flags == 0) enqueue(rp);
00677 }
00678 else {
00679 ticks_added += rp->p_quantum_size - rp->p_ticks_left;
00680 rp->p_ticks_left = rp->p_quantum_size;
00681 }
00682 unlock(5);
00683 }
00684 }
00685 #if DEBUG
00686 kprintf("ticks_added: %d\n", ticks_added);
00687 #endif
00688
00689
00690
00691
00692 next_period = MAX(Q_BALANCE_TICKS, ticks_added);
00693 set_timer(&queue_timer, get_uptime() + next_period, balance_queues);
00694 }
00695
00696
00697
00698
00699 PUBLIC int lock_send(dst_e, m_ptr)
00700 int dst_e;
00701 message *m_ptr;
00702 {
00703
00704 int result;
00705 lock(2, "send");
00706 result = mini_send(proc_ptr, dst_e, m_ptr, NON_BLOCKING);
00707 unlock(2);
00708 return(result);
00709 }
00710
00711
00712
00713
00714 PUBLIC void lock_enqueue(rp)
00715 struct proc *rp;
00716 {
00717
00718 lock(3, "enqueue");
00719 enqueue(rp);
00720 unlock(3);
00721 }
00722
00723
00724
00725
00726 PUBLIC void lock_dequeue(rp)
00727 struct proc *rp;
00728 {
00729
00730 if (k_reenter >= 0) {
00731
00732
00733
00734 dequeue(rp);
00735 } else {
00736 lock(4, "dequeue");
00737 dequeue(rp);
00738 unlock(4);
00739 }
00740 }
00741
00742
00743
00744
00745 #if DEBUG_ENABLE_IPC_WARNINGS
00746 PUBLIC int isokendpt_f(file, line, e, p, fatalflag)
00747 char *file;
00748 int line;
00749 #else
00750 PUBLIC int isokendpt_f(e, p, fatalflag)
00751 #endif
00752 int e, *p, fatalflag;
00753 {
00754 int ok = 0;
00755
00756
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767
00768 *p = _ENDPOINT_P(e);
00769 if(!isokprocn(*p)) {
00770 #if DEBUG_ENABLE_IPC_WARNINGS
00771 kprintf("kernel:%s:%d: bad endpoint %d: proc %d out of range\n",
00772 file, line, e, *p);
00773 #endif
00774 } else if(isemptyn(*p)) {
00775 #if DEBUG_ENABLE_IPC_WARNINGS
00776 kprintf("kernel:%s:%d: bad endpoint %d: proc %d empty\n", file, line, e, *p);
00777 #endif
00778 } else if(proc_addr(*p)->p_endpoint != e) {
00779 #if DEBUG_ENABLE_IPC_WARNINGS
00780 kprintf("kernel:%s:%d: bad endpoint %d: proc %d has ept %d (generation %d vs. %d)\n", file, line,
00781 e, *p, proc_addr(*p)->p_endpoint,
00782 _ENDPOINT_G(e), _ENDPOINT_G(proc_addr(*p)->p_endpoint));
00783 #endif
00784 } else ok = 1;
00785 if(!ok && fatalflag) {
00786 panic("invalid endpoint ", e);
00787 }
00788 return ok;
00789 }
00790