/*------------------------------------------------------------------------ * semreset - Reset a semaphore's count and release waiting processes *------------------------------------------------------------------------ */ syscall semreset( sid32 sem, /* ID of semaphore to reset */ int32 count /* New count (must be >= 0) */ ) { intmask mask; /* Saved interrupt mask */ struct sentry *semptr; /* Ptr to semaphore table entry */ qid16 semqueue; /* Semaphore's process queue ID */ pid32 pid; /* ID of a waiting process */ mask = disable(); if (count < 0 || isbadsem(sem) || semtab[sem].sstate==S_FREE) { restore(mask); return SYSERR; } semptr = &semtab[sem]; semqueue = semptr->squeue; /* Free any waiting processes */ resched_cntl(DEFER_START); while ((pid=getfirst(semqueue)) != EMPTY) ready(pid); semptr->scount = count; /* Reset count as specified */ resched_cntl(DEFER_STOP); restore(mask); return OK; }
/*------------------------------------------------------------------------ * alarmwakeup - Called by clock interrupt handler to awaken processes to call alarm handler *------------------------------------------------------------------------ */ void alarmwakeup(void) { /* LAB 4Q3 Awaken all processes that have no more time to sleep */ resched_cntl(DEFER_START); while (alarmnonempty(alarmq) && (alarmfirstkey(alarmq) <= 0)) { pid32 timeoutProcess = alarmdequeue(alarmq); // LAB 4Q3 If current process then just invoke the callback function if (timeoutProcess == currpid) { struct procent *prptr = &proctab[currpid]; void (*alarmFunction) () = prptr->alarmfunc; prptr->alarmtime = 0; prptr->alarmTimeOut = FALSE; alarmFunction(); prptr->alarmfunc = NULL; } else { // LAB 4Q3 if not the current process then ready the process frocibly in order to run the // alarm callback function context switch in. struct procent *prptr = &proctab[timeoutProcess]; prptr->alarmTimeOut = TRUE; if (prptr->prstate == PR_SLEEP) { unsleep(timeoutProcess); ready(timeoutProcess); } } } resched_cntl(DEFER_STOP); return; }
/*------------------------------------------------------------------------ * udp_release - Release a previously-registered UDP slot *------------------------------------------------------------------------ */ status udp_release ( uid32 slot /* Table slot to release */ ) { intmask mask; /* Saved interrupt mask */ struct udpentry *udptr; /* Pointer to udptab entry */ struct netpacket *pkt; /* pointer to packet being read */ /* Ensure only one process can access the UDP table at a time */ mask = disable(); /* Verify that the slot is valid */ if ( (slot < 0) || (slot >= UDP_SLOTS) ) { restore(mask); return SYSERR; } /* Get pointer to table entry */ udptr = &udptab[slot]; /* Verify that the slot has been registered and is valid */ if (udptr->udstate == UDP_FREE) { restore(mask); return SYSERR; } /* Defer rescheduling to prevent freebuf from switching context */ resched_cntl(DEFER_START); while (udptr->udcount > 0) { pkt = udptr->udqueue[udptr->udhead++]; if (udptr->udhead >= UDP_QSIZ) { udptr->udhead = 0; } freebuf((char *)pkt); udptr->udcount--; } udptr->udstate = UDP_FREE; resched_cntl(DEFER_STOP); restore(mask); return OK; }
/*------------------------------------------------------------------------ * icmp_release - Release a previously-registered ICMP icmpid *------------------------------------------------------------------------ */ status icmp_release ( int32 icmpid /* Slot in icmptab to release */ ) { intmask mask; /* Saved interrupt mask */ struct icmpentry *icmptr; /* Pointer to icmptab entry */ struct netpacket *pkt; /* Pointer to packet */ mask = disable(); /* Check arg and insure entry in table is in use */ if ( (icmpid < 0) || (icmpid >= ICMP_SLOTS) ) { restore(mask); return SYSERR; } icmptr = &icmptab[icmpid]; if (icmptr->icstate != ICMP_USED) { restore(mask); return SYSERR; } /* Remove each packet from the queue and free the buffer */ resched_cntl(DEFER_START); while (icmptr->iccount > 0) { pkt = icmptr->icqueue[icmptr->ichead++]; if (icmptr->ichead >= ICMP_SLOTS) { icmptr->ichead = 0; } freebuf((char *)pkt); icmptr->iccount--; } /* Mark the entry free */ icmptr->icstate = ICMP_FREE; resched_cntl(DEFER_STOP); restore(mask); return OK; }
/*------------------------------------------------------------------------ * ttyhandler - Handle an interrupt for a tty (serial) device *------------------------------------------------------------------------ */ void ttyhandler(uint32 xnum) { struct dentry *devptr; /* Address of device control blk*/ struct ttycblk *typtr; /* Pointer to ttytab entry */ struct uart_csreg *csrptr; /* Address of UART's CSR */ uint32 iir = 0; /* Interrupt identification */ uint32 lsr = 0; /* Line status */ /* Get CSR address of the device (assume console for now) */ devptr = (struct dentry *) &devtab[CONSOLE]; csrptr = (struct uart_csreg *) devptr->dvcsr; /* Obtain a pointer to the tty control block */ typtr = &ttytab[ devptr->dvminor ]; /* Decode hardware interrupt request from UART device */ /* Check interrupt identification register */ iir = csrptr->iir; if (iir & UART_IIR_IRQ) { return; } /* Decode the interrupt cause based upon the value extracted */ /* from the UART interrupt identification register. Clear */ /* the interrupt source and perform the appropriate handling */ /* to coordinate with the upper half of the driver */ /* Decode the interrupt cause */ iir &= UART_IIR_IDMASK; /* Mask off the interrupt ID */ switch (iir) { /* Receiver line status interrupt (error) */ case UART_IIR_RLSI: lsr = csrptr->lsr; if(lsr & UART_LSR_BI) { /* Break Interrupt */ lsr = csrptr->buffer; /* Read the RHR register to acknowledge */ } return; /* Receiver data available or timed out */ case UART_IIR_RDA: case UART_IIR_RTO: resched_cntl(DEFER_START); /* While chars avail. in UART buffer, call ttyhandle_in */ while ( (csrptr->lsr & UART_LSR_DR) != 0) { ttyhandle_in(typtr, csrptr); } resched_cntl(DEFER_STOP); return; /* Transmitter output FIFO is empty (i.e., ready for more) */ case UART_IIR_THRE: ttyhandle_out(typtr, csrptr); return; /* Modem status change (simply ignore) */ case UART_IIR_MSC: return; } }