static void demo_thread_1() { int times = 3; kprintf("Thread '%s' started.\n", thread_self()->td_name); do { thread_switch_to(td2); kprintf("Thread '%s' running.\n", thread_self()->td_name); } while (--times); thread_switch_to(td0); }
void __init kern_start() { struct thread *main_thread; mach_start(); kprintf("Starting Koowaldah v%s kernel.\n", VERSION_STRING); /* memory allocation machinery: zones, buddy allocator, slices */ init_mem_info(); paging_init(); galloc_init(); kqueue_init(); timers_init(); sched0_load(); scheduler_init(); main_thread = thread_create(&kernel_main_thread, "GOD", NULL); if (!main_thread) { kprintf("Failed to create main kernel thread\n"); bug(); } thread_switch_to(main_thread); bug(); }
static void demo_thread_2() { int times = 3; kprintf("Thread '%s' started.\n", thread_self()->td_name); do { thread_switch_to(td1); kprintf("Thread '%s' running.\n", thread_self()->td_name); } while (--times); panic("This line need not be reached!"); }
int main() { kprintf("Thread '%s' started.\n", thread_self()->td_name); td0 = thread_self(); td1 = thread_create("first", demo_thread_1, NULL); td2 = thread_create("second", demo_thread_2, NULL); thread_switch_to(td1); kprintf("Thread '%s' running.\n", thread_self()->td_name); assert(td0 == thread_get_by_tid(td0->td_tid)); assert(td1 == thread_get_by_tid(td1->td_tid)); assert(td2 == thread_get_by_tid(td2->td_tid)); assert(NULL == thread_get_by_tid(1234)); thread_dump_all(); thread_delete(td2); thread_delete(td1); return 0; }
PRIVATE u8_t syscall_receive(struct thread* th_receiver, struct proc* proc_sender) { struct thread* th_available = NULL; /* Set receive state */ th_receiver->ipc.state |= SYSCALL_IPC_RECEIVING; /* Set thread to receive from (can be NULL) */ th_receiver->ipc.recv_from = proc_sender; /* Find a thread sending to me */ th_available = syscall_find_waiting_sender(th_receiver->proc, proc_sender); /* A matching sender found ? */ if ( th_available != NULL ) { /* Copy message from sender to receiver */ syscall_copymsg(th_available,th_receiver); arch_printf("%u receives a message from %u\n",th_receiver->proc->pid,th_available->proc->pid); /* Unblock sender */ th_available->state = THREAD_READY; /* Set end of sending */ th_available->ipc.state &= ~SYSCALL_IPC_SENDING; /* Remove sender from receiver waiting list et set it as ready for scheduling */ LLIST_REMOVE(th_receiver->proc->wait_list, th_available); sched_enqueue(SCHED_READY_QUEUE, th_available); arch_printf("%u unblock %u from its wait list\n",th_receiver->proc->pid,th_available->proc->pid); /* End of reception */ th_receiver->ipc.state &= ~SYSCALL_IPC_RECEIVING; } else { /* No matching sender found: blocked waiting for a sender */ th_receiver->state = THREAD_BLOCKED; /* Sched queues manipulation */ sched_dequeue(SCHED_READY_QUEUE, th_receiver); sched_enqueue(SCHED_BLOCKED_QUEUE, th_receiver); arch_printf("%u blocked cause no message available\n",th_receiver->proc->pid); /* Current thread (receiver) is blocked, need scheduling */ struct thread* th; th = sched_elect(); /* Change address space */ if (th->proc) { arch_switch_addrspace(th->proc->addrspace); } thread_switch_to(th); } return IPC_SUCCESS; }
PRIVATE u8_t syscall_send(struct thread* th_sender, struct proc* proc_receiver) { struct thread* th_receiver; /* There must be a receiver - No broadcast allow */ if ( proc_receiver == NULL ) { arch_printf("send failed 1\n"); return IPC_FAILURE; } /* Check for deadlock */ if (syscall_deadlock(th_sender->proc,proc_receiver) == IPC_FAILURE) { arch_printf("deadlock\n"); return IPC_FAILURE; } /* No deadlock here, set state */ th_sender->ipc.state |= SYSCALL_IPC_SENDING; /* Set destination */ th_sender->ipc.send_to = proc_receiver; /* Get a thread willing to receive the message */ th_receiver = syscall_find_receiver(proc_receiver,th_sender->proc); if (th_receiver != NULL) { /* Found a thread ! copy message from sender to receiver */ syscall_copymsg(th_sender,th_receiver); arch_printf("%u sends a message to %u\n",th_sender->proc->pid,proc_receiver->pid); /* Set end of reception */ th_receiver->ipc.state &= ~SYSCALL_IPC_RECEIVING; /* Ready for scheduling */ th_receiver->state = THREAD_READY; /* Scheduler queues manipulations */ sched_dequeue(SCHED_BLOCKED_QUEUE, th_receiver); sched_enqueue(SCHED_READY_QUEUE, th_receiver); arch_printf("%u unblock %u after send\n",th_sender->proc->pid,proc_receiver->pid); /* Message is delivered to receiver, set end of sending */ th_sender->ipc.state &= ~SYSCALL_IPC_SENDING; /* Scheduler queues manipulations (blocks sender) */ sched_dequeue(SCHED_READY_QUEUE, th_sender); sched_enqueue(SCHED_BLOCKED_QUEUE, th_sender); } else { /* No receiving thread, enqueue in wait list */ sched_dequeue(SCHED_READY_QUEUE, th_sender); LLIST_ADD(proc_receiver->wait_list,th_sender); arch_printf("%u in wait list of %u\n",th_sender->proc->pid,proc_receiver->pid); } /* Sender is blocked, waiting for message processing (must be unblocked via notify) */ arch_printf("%u block after send\n",th_sender->proc->pid); th_sender->state = THREAD_BLOCKED; /* In any cases, current thread (sender) is blocked, so scheduling is needing */ struct thread* th; th = sched_elect(); /* Change address space */ if (th->proc) { arch_switch_addrspace(th->proc->addrspace); } thread_switch_to(th); return IPC_SUCCESS; }