/* procedure to poll the event queue for timer events, run by the clock thread; on a timer event, call "send_interrupt()" to run the system thread's clock handler routine */ DWORD WINAPI clock_poll(LPVOID arg) { #ifdef WINCE for(;;) { Sleep(PERIOD/1000); /* sleep requires time in milliseconds */ send_interrupt(CLOCK_INTERRUPT_TYPE, NULL); } #else LARGE_INTEGER i; HANDLE timer; /* HANDLE thread = GetCurrentThread(); */ char name[64]; sprintf(name, "timer %d", pid); timer = CreateWaitableTimer(NULL, TRUE, name); assert(timer != NULL); for (;;) { i.QuadPart = -PERIOD*10; /* NT timer values are in hundreds of nanoseconds */ AbortOnError(SetWaitableTimer(timer, &i, 0, NULL, NULL, FALSE)); if (WaitForSingleObject(timer, INFINITE) == WAIT_OBJECT_0) { if (DEBUG) kprintf("CLK: clock tick.\n"); send_interrupt(CLOCK_INTERRUPT_TYPE, NULL); } } #endif /* never reached */ return 0; }
/* Basically, this function is guaranteed to return * when the target CPU/scheduler is locked for you to * use. */ void sched_lock( int cpu_id, int complete ) { int lock = 0; assert( (cpu_id >= 0) && (cpu_id < cpu_count) ); assert( ! ((CPUID == cpu_id) && (complete == 1 )) ); // Because a complete lock requires the scheduler to halt // the running thread. But if the thread is running on the // same CPU and it's halted, then we're in trouble. //if ( CPUID == cpu_id ) lock = disable_interrupts(); lock = disable_interrupts(); acquire_spinlock( &(cpu[ cpu_id ].sched.lock_scheduler) ); cpu[ cpu_id ].sched.lock_flags = lock; // If it's idle, wake it up.. if ( cpu[ cpu_id ].sched.idle != 0 ) { // Mark it as not-idle and wake it up. cpu[ cpu_id ].sched.idle = 0; send_interrupt( cpu_id, APIC_INTERRUPT ); } if ( complete == 1 ) { while ( cpu[ cpu_id ].sched.running != 0 ); } assert( cpu[ cpu_id ].sched.nested_lock++ == 0 ); }
int WINAPI read_poll(void* arg) { struct kb_line* new_node; while (1) { new_node = (struct kb_line*) malloc(sizeof(struct kb_line)); new_node->next = NULL; fgets(new_node->buf, MAX_LINE_LENGTH, stdin); #ifdef WINCE if(new_node->buf[0] != 0) send_interrupt(READ_INTERRUPT_TYPE, new_node); #else send_interrupt(READ_INTERRUPT_TYPE, new_node); #endif } }
static void check_timeout(int index) { struct timeval tv; if (!eth_timeout_flags[index]) return; if (gettimeofday(&tv, NULL) != 0) return; if (TIMEVAL_CMP(tv, eth_timeout[index]) < 1) return; send_interrupt(index); eth_timeout_flags[index] = 0; }
int read_poll(void* arg) { struct kb_line* new_node; while (1) { new_node = (struct kb_line*) malloc(sizeof(struct kb_line)); new_node->next = NULL; fgets(new_node->buf, MAX_LINE_LENGTH, stdin); send_interrupt(READ_INTERRUPT_TYPE, read_handler, new_node); } }
/* procedure to poll the event queue for timer events, run by the clock thread; on a timer event, call "send_interrupt()" to run the system thread's clock handler routine */ DWORD WINAPI clock_poll(LPVOID arg) { #ifdef WINCE Sleep(PERIOD/1000); /* sleep requires time in milliseconds */ send_interrupt(CLOCK_INTERRUPT_TYPE, NULL); #else LARGE_INTEGER i; HANDLE timer; /* HANDLE thread = GetCurrentThread(); */ char name[32]; sprintf(name, "timer %d", pid); timer = CreateWaitableTimer(NULL, TRUE, name); assert(timer != NULL); WaitOnObject(clock_poll_done); while (clock_enabled) { i.QuadPart = -PERIOD*10; /* NT timer values are in hundreds of nanoseconds */ AbortOnError(SetWaitableTimer(timer, &i, 0, NULL, NULL, FALSE)); if (WaitForSingleObject(timer, INFINITE) == WAIT_OBJECT_0) { //if (DEBUG) //kprintf("CLK: clock tick.\n"); ticks++; clock_enabled ? send_interrupt(CLOCK_INTERRUPT_TYPE, NULL): clock_enabled; } } dbgprintf("...clock interrupts stopped.\n"); ReleaseMutex(clock_poll_done); #endif return 0; }
/* * receive incoming packets from the specified socket, translate their * addresses to network_address_t type, and call the user-supplied handler * * a network interrupt disables interrupts, so that we can cleanly return. * if interrupts were not disabled, and we were hit by a clock interrupt, it * would not be possible to return until we returned to the original stack. * this is inelegant, but we are constrained by ignorance of the minithread * struct format! */ int WINAPI network_poll(void* arg) { SOCKET* s; network_interrupt_arg_t* packet; struct sockaddr_in addr; int fromlen = sizeof(struct sockaddr_in); s = (SOCKET *) arg; for (;;) { /* we rely on run_user_handler to destroy this data structure */ if (DEBUG) kprintf("NET:Allocating an incoming packet.\n"); packet = (network_interrupt_arg_t *) malloc(sizeof(network_interrupt_arg_t)); assert(packet != NULL); packet->size = recvfrom(*s, packet->buffer, MAX_NETWORK_PKT_SIZE, 0, (struct sockaddr *) &addr, &fromlen); if (packet->size <= 0) { if(WSAGetLastError() == 10054){ kprintf("NET: Broadcst attempt rejected (Are all my neighbors running?)\n"); free(packet); continue; } else { kprintf("NET:Error, %d.\n", WSAGetLastError()); AbortOnCondition(1,"Crashing."); } } else if (DEBUG) kprintf("NET:Received a packet, seqno %ld.\n", ntohl(*((int *) packet->buffer))); assert(fromlen == sizeof(struct sockaddr_in)); sockaddr_to_network_address(&addr, packet->addr); /* * now we have filled in the arg to the network interrupt service routine, * so we have to get the user's thread to run it. */ if (DEBUG) kprintf("NET:packet arrived.\n"); send_interrupt(NETWORK_INTERRUPT_TYPE, (void*)packet); } }
int network_poll(void* arg) { int* s; network_interrupt_arg_t* packet; struct sockaddr_in addr; int fromlen = sizeof(struct sockaddr_in); s = (int *) arg; for (;;) { /* we rely on run_user_handler to destroy this data structure */ if (DEBUG) kprintf("NET:Allocating an incoming packet.\n"); packet = (network_interrupt_arg_t *) malloc(sizeof(network_interrupt_arg_t)); assert(packet != NULL); packet->size = recvfrom(*s, packet->buffer, MAX_NETWORK_PKT_SIZE, 0, (struct sockaddr *) &addr, (socklen_t*) &fromlen); if (packet->size < 0) { kprintf("NET:Error, %d.\n", errno); AbortOnCondition(1,"Crashing."); } else if (DEBUG) kprintf("NET:Received a packet, seqno %ld.\n", (long) ntohl(*((int *) packet->buffer))); assert(fromlen == sizeof(struct sockaddr_in)); sockaddr_to_network_address(&addr, packet->addr); /* * now we have filled in the arg to the network interrupt service routine, * so we have to get the user's thread to run it. */ if (DEBUG) kprintf("NET:packet arrived.\n"); send_interrupt(NETWORK_INTERRUPT_TYPE, (void*)packet); } }
/* handle read and write to disk. Watch the job queue and submit the requests to the operating system one by one. On completion, the user suplied function with the user suplied parameter is called The interrupt mechanism is used much like in the network case. One such process per disk. The argument is a disk_t with the disk description. */ void disk_poll(void* arg) { enum { DISK_OK, DISK_CRASHED } disk_state; disk_t* disk = (disk_t*) arg; disk_layout_t layout; disk_interrupt_arg_t* disk_interrupt; disk_queue_elem_t* disk_request; disk_state=DISK_OK; for (;;){ int blocknum; char* buffer; disk_request_type_t type; int offset; /* We use mutex to protect queue handling, as should the code that inserts requests in the queue */ /* wait for somebody to put something in the queue */ sem_wait(&disk->semaphore); if (DEBUG) kprintf("Disk Controler: got a request.\n"); /* get exclusive access to queue handling and dequeue a request */ pthread_mutex_lock(&disk_mutex); layout = disk->layout; /* this is the layout used until the request is fulfilled */ /* this is safe since a disk can only grow */ if (disk->queue != NULL){ disk_interrupt = (disk_interrupt_arg_t*) malloc(sizeof(disk_interrupt_arg_t)); assert( disk_interrupt != NULL); disk_interrupt->disk = disk; /* we look first at the first request in the queue to see if it is special. */ disk_interrupt->request = disk->queue->request; /* check if we shut down the disk */ if (disk->queue->request.type == DISK_SHUTDOWN){ if (DEBUG) kprintf("Disk: Shutting down.\n"); disk_interrupt->reply=DISK_REPLY_OK; fclose(disk->file); pthread_mutex_unlock(&disk_mutex); sem_destroy(&disk->semaphore); send_interrupt(DISK_INTERRUPT_TYPE, mini_disk_handler, (void*)disk_interrupt); break; /* end the disk task */ } /* check if we got to reset the disk */ if (disk->queue->request.type == DISK_RESET){ disk_queue_elem_t* curr; disk_queue_elem_t *next; if (DEBUG) kprintf("Disk: Resetting.\n"); disk_interrupt->reply=DISK_REPLY_OK; /* empty the queue */ curr=disk->queue; while (curr!=NULL){ next=curr->next; free(curr); curr=next; } disk->queue = disk->last = NULL; disk_state = DISK_OK; pthread_mutex_unlock(&disk_mutex); goto sendinterrupt; } /* permute the first two elements in the queue probabilistically if queue has two elements */ if (disk->queue->next !=NULL && (genrand() < reordering_rate)){ disk_queue_elem_t* first = disk->queue; disk_queue_elem_t* second = first->next; first->next = second->next; second->next = first; disk->queue = second; if (disk->last == second) disk->last = first; } /* dequeue the first request */ disk_request = disk->queue; disk->queue = disk_request->next; if (disk->queue == NULL) disk->last = NULL; } else { /* empty queue, release the lock and leave */ pthread_mutex_unlock(&disk_mutex); break; } pthread_mutex_unlock(&disk_mutex); disk_interrupt->request = disk_request->request; /* crash the disk ocasionally */ if (genrand() < crash_rate){ disk_state = DISK_CRASHED; /* if (DEBUG) */ kprintf("Disk: Crashing disk.\n"); } /* check if disk crashed */ if (disk_state == DISK_CRASHED){ disk_interrupt->reply=DISK_REPLY_CRASHED; goto sendinterrupt; } if ( genrand() < failure_rate ) { /* Trash the request */ disk_interrupt->reply = DISK_REPLY_FAILED; if (DEBUG) kprintf("Disk: Request failed.\n"); goto sendinterrupt; } /* Check validity of request */ disk_interrupt->reply = DISK_REPLY_OK; blocknum = disk_request->request.blocknum; buffer = disk_request->request.buffer; type = disk_request->request.type; if (DEBUG) kprintf("Disk Controler: got a request for block %d type %d .\n", blocknum, type); /* If we got here is a read or a write request */ offset = DISK_BLOCK_SIZE*(blocknum + 1); if ( (blocknum >= layout.size) || (fseek(disk->file, offset, SEEK_SET) != 0) ) { disk_interrupt->reply = DISK_REPLY_ERROR; if (DEBUG) kprintf("Disk Controler: Block too big or failed fseek, block=%d, offset=%d, disk_size=%d.\n", blocknum, offset, layout.size); goto sendinterrupt; } switch (type) { case DISK_READ: if (fread(buffer, 1, DISK_BLOCK_SIZE, disk->file) < DISK_BLOCK_SIZE) disk_interrupt->reply = DISK_REPLY_ERROR; if (DEBUG) kprintf("Disk: Read request.\n"); break; case DISK_WRITE: if (fwrite(buffer, 1, DISK_BLOCK_SIZE, disk->file) < DISK_BLOCK_SIZE) disk_interrupt->reply = DISK_REPLY_ERROR; fflush(disk->file); if (DEBUG) kprintf("Disk: Write request.\n"); break; default: break; } sendinterrupt: if (DEBUG) kprintf("Disk Controler: sending an interrupt for block %d, request type %d, with reply %d.\n", disk_interrupt->request.blocknum, disk_interrupt->request.type, disk_interrupt->reply); send_interrupt(DISK_INTERRUPT_TYPE, mini_disk_handler, (void*)disk_interrupt); } }
int canon(char *ep, int c) { if(c&0200) return(SCROLL); switch(c) { case '\b': if(sendp > sendbuf) sendp--; *ep++ = '\b'; *ep++ = ' '; *ep++ = '\b'; break; case 0x15: /* ^U line kill */ sendp = sendbuf; *ep++ = '^'; *ep++ = 'U'; *ep++ = '\n'; break; case 0x17: /* ^W word kill */ while(sendp > sendbuf && !alnum(*sendp)) { *ep++ = '\b'; *ep++ = ' '; *ep++ = '\b'; sendp--; } while(sendp > sendbuf && alnum(*sendp)) { *ep++ = '\b'; *ep++ = ' '; *ep++ = '\b'; sendp--; } break; case '\177': /* interrupt */ sendp = sendbuf; send_interrupt(); return(NEWLINE); case '\021': /* quit */ case '\r': case '\n': if(sendp < &sendbuf[512]) *sendp++ = '\n'; sendnchars((int)(sendp-sendbuf), sendbuf); sendp = sendbuf; if(c == '\n' || c == '\r') { *ep++ = '\n'; } *ep = 0; return(NEWLINE); case '\004': /* EOT */ if(sendp == sendbuf) { sendnchars(0,sendbuf); *ep = 0; return(NEWLINE); } /* fall through */ default: if(sendp < &sendbuf[512]) *sendp++ = c; *ep++ = c; break; } *ep = 0; return(OTHER); }