static void global_tests(uint32_t vcoreid) { int retval; switch (test) { case TEST_YIELD_ALL: printf("Core %d yielding\n", vcoreid); sys_yield(0); // should be RUNNABLE_M now, amt_wanted == 1 while(1); case TEST_SWITCH_TO_RUNNABLE_S: if (vcoreid == 2) { printf("Core %d trying to request 0/ switch to _S\n", vcoreid); udelay(3000000); retval = vcore_request(0); // will only see this if we are scheduled() printf("Core %d back up! (retval:%d)\n", vcoreid, retval); printf("And exiting\n"); exit(0); } while(1); case TEST_CRAZY_YIELDS: udelay(300000*vcoreid); vcore_request(5); sys_yield(0); printf("should never see me, unless you slip into *_S\n"); break; case TEST_CONCURRENT_SYSCALLS: for (int i = 0; i < 10; i++) { for (int j = 0; j < 100; j++) sys_null(); printf("Hello from vcore %d, iteration %d\n", vcoreid, i); } break; } }
int main(int argc, char** argv) { uint32_t vcoreid = vcore_id(); int retval = 0; mcs_barrier_init(&b, max_vcores()); /* begin: stuff userspace needs to do before switching to multi-mode */ vcore_lib_init(); #if 0 /* tell the kernel where and how we want to receive notifications */ struct notif_method *nm; for (int i = 0; i < MAX_NR_NOTIF; i++) { nm = &__procdata.notif_methods[i]; nm->flags |= NOTIF_WANTED | NOTIF_MSG | NOTIF_IPI; nm->vcoreid = i % 2; // vcore0 or 1, keepin' it fresh. } #endif /* Need to save this somewhere that you can find it again when restarting * core0 */ core0_tls = get_tls_desc(0); /* Need to save our floating point state somewhere (like in the * user_thread_tcb so it can be restarted too */ /* end: stuff userspace needs to do before switching to multi-mode */ /* get into multi mode */ retval = vcore_request(1); if (retval) printf("F****d!\n"); printf("Proc %d requesting another vcore\n", getpid()); begin = read_tsc(); retval = vcore_request(1); if (retval) printf("F****d!\n"); while (!core1_up) cpu_relax; end = read_tsc(); printf("Took %llu usec (%llu nsec) to receive 1 core (cold).\n", udiff(begin, end), ndiff(begin, end)); printf("[T]:002:%llu:%llu:1:C.\n", udiff(begin, end), ndiff(begin, end)); core1_up = FALSE; udelay(2000000); printf("Proc %d requesting the vcore again\n", getpid()); begin = read_tsc(); retval = vcore_request(1); if (retval) printf("F****d!\n"); while (!core1_up) cpu_relax(); end = read_tsc(); printf("Took %llu usec (%llu nsec) to receive 1 core (warm).\n", udiff(begin, end), ndiff(begin, end)); printf("[T]:002:%llu:%llu:1:W.\n", udiff(begin, end), ndiff(begin, end)); return 0; }
void ghetto_vcore_entry(void) { uint32_t vcoreid = vcore_id(); static bool first_time = TRUE; temp = 0xcafebabe; /* vcore_context test (don't need to do this anywhere) */ assert(in_vcore_context()); /* old logic was moved to parlib code */ if (current_uthread) { assert(vcoreid == 0); run_current_uthread(); } /* unmask notifications once you can let go of the notif_tf and it is okay * to clobber the transition stack. * Check Documentation/processes.txt: 4.2.4. In real code, you should be * popping the tf of whatever user process you want (get off the x-stack) */ enable_notifs(vcoreid); /* end: stuff userspace needs to do to handle notifications */ printf("Hello from vcore_entry in vcore %d with temp addr %p and temp %p\n", vcoreid, &temp, temp); vcore_request(1); //mcs_barrier_wait(&b,vcore_id()); udelay(vcoreid * 10000000); //exit(0); while(1); }
/* GIANT WARNING: if you make any changes to this, also change the broadcast * wakeups (cond var, barrier, etc) */ static void pth_thread_runnable(struct uthread *uthread) { struct pthread_tcb *pthread = (struct pthread_tcb*)uthread; /* At this point, the 2LS can see why the thread blocked and was woken up in * the first place (coupling these things together). On the yield path, the * 2LS was involved and was able to set the state. Now when we get the * thread back, we can take a look. */ printd("pthread %08p runnable, state was %d\n", pthread, pthread->state); switch (pthread->state) { case (PTH_CREATED): case (PTH_BLK_YIELDING): case (PTH_BLK_JOINING): case (PTH_BLK_SYSC): case (PTH_BLK_PAUSED): case (PTH_BLK_MUTEX): /* can do whatever for each of these cases */ break; default: printf("Odd state %d for pthread %08p\n", pthread->state, pthread); } pthread->state = PTH_RUNNABLE; /* Insert the newly created thread into the ready queue of threads. * It will be removed from this queue later when vcore_entry() comes up */ mcs_pdr_lock(&queue_lock); /* Again, GIANT WARNING: if you change this, change batch wakeup code */ TAILQ_INSERT_TAIL(&ready_queue, pthread, tq_next); threads_ready++; mcs_pdr_unlock(&queue_lock); /* Smarter schedulers should look at the num_vcores() and how much work is * going on to make a decision about how many vcores to request. */ if (can_adjust_vcores) vcore_request(threads_ready); }
int main(int argc, char** argv) { uint32_t vcoreid; int nr_vcores; if (argc < 2) nr_vcores = max_vcores(); else nr_vcores = atoi(argv[1]); /* Inits a thread for us, though we won't use it. Just a hack to get into * _M mode. Note this requests one vcore for us */ struct uthread dummy = {0}; uthread_2ls_init(&dummy, &ghetto_sched_ops); uthread_mcp_init(); /* Reset the blockon to be the spinner... This is really shitty. Any * blocking calls after we become an MCP and before this will fail. This is * just mhello showing its warts due to trying to work outside uthread.c */ ros_syscall_blockon = __ros_syscall_spinon; vcore_request(nr_vcores - 1); /* since we already have 1 */ while (1) sys_halt_core(0); return 0; }
int main(int argc, char** argv) { struct timeval start_tv = {0}; struct timeval end_tv = {0}; long usec_diff; long nr_ctx_switches; if (argc > 1) nr_yield_threads = strtol(argv[1], 0, 10); if (argc > 2) nr_yield_loops = strtol(argv[2], 0, 10); if (argc > 3) nr_vcores = strtol(argv[3], 0, 10); if (argc > 4) amt_fake_work = strtol(argv[4], 0, 10); nr_yield_threads = MIN(nr_yield_threads, MAX_NR_TEST_THREADS); printf("Making %d threads of %d loops each, on %d vcore(s), %d work\n", nr_yield_threads, nr_yield_loops, nr_vcores, amt_fake_work); /* OS dependent prep work */ if (nr_vcores) { /* Only do the vcore trickery if requested */ vcore_request(nr_vcores - 1); /* ghetto incremental interface */ for (int i = 0; i < nr_vcores; i++) { printf("Vcore %d not mapped to a particular pcore\n", i); } } /* create and join on yield */ for (int i = 0; i < nr_yield_threads; i++) { printd("[A] About to create thread %d\n", i); assert(!upthread_create(&my_threads[i], NULL, &yield_thread, (void*)(long)i)); } if (gettimeofday(&start_tv, 0)) perror("Start time error..."); ready = TRUE; /* signal to any spinning uthreads to start */ for (int i = 0; i < nr_yield_threads; i++) { printd("[A] About to join on thread %d(%p)\n", i, my_threads[i]); upthread_join(my_threads[i], &my_retvals[i]); printd("[A] Successfully joined on thread %d (retval: %p)\n", i, my_retvals[i]); } if (gettimeofday(&end_tv, 0)) perror("End time error..."); nr_ctx_switches = nr_yield_threads * nr_yield_loops; usec_diff = (end_tv.tv_sec - start_tv.tv_sec) * 1000000 + (end_tv.tv_usec - start_tv.tv_usec); printf("Done: %d uthreads, %d loops, %d vcores, %d work\n", nr_yield_threads, nr_yield_loops, nr_vcores, amt_fake_work); printf("Nr context switches: %ld\n", nr_ctx_switches); printf("Time to run: %ld usec\n", usec_diff); if (nr_vcores == 1) printf("Context switch latency: %d nsec\n", (int)(1000LL*usec_diff / nr_ctx_switches)); printf("Context switches / sec: %d\n\n", (int)(1000000LL*nr_ctx_switches / usec_diff)); }
void pth_thread_runnable(struct uthread *uthread) { struct pthread_tcb *pthread = (struct pthread_tcb*)uthread; struct mcs_lock_qnode local_qn = {0}; /* Insert the newly created thread into the ready queue of threads. * It will be removed from this queue later when vcore_entry() comes up */ mcs_lock_notifsafe(&queue_lock, &local_qn); TAILQ_INSERT_TAIL(&ready_queue, pthread, next); threads_ready++; mcs_unlock_notifsafe(&queue_lock, &local_qn); /* Smarter schedulers should look at the num_vcores() and how much work is * going on to make a decision about how many vcores to request. */ vcore_request(threads_ready); }
void vcore_entry(void) { uint32_t vcoreid; static int first_time = 1; // used by vcore2 int retval; vcoreid = vcore_id(); printf("Hello from vcore_entry in vcore %d\n", vcoreid); if ((vcoreid == 2) && first_time) { first_time = 0; switch (test) { case TEST_INCREMENTAL_CHANGES: // Testing asking for less than we already have udelay(1000000); printf("Asking for too few:\n"); retval = vcore_request(2); printf("Should be -EINVAL(7): %d\n", retval); // Testing getting more while running printf("Asking for more while running:\n"); udelay(1000000); retval = vcore_request(5); printf("core2's retval: %d\n", retval); break; case TEST_YIELD_OUT_OF_ORDER: printf("Core %d yielding\n", vcoreid); sys_yield(0); break; case TEST_YIELD_0_OUT_OF_ORDER: udelay(7500000); printf("Core 0 should have yielded, asking for another\n"); retval = vcore_request(5); } } global_tests(vcoreid); printf("Vcore %d Done!\n", vcoreid); }
/* Test program for the audio device. mmap()s the stuff, sets up a notif * handler, and switches to multi_mode. * * Note: this has a lot of mhello-like MCP infrastructure. When Lithe is * working, you won't need any of this. Just the mmap stuff and the notif * handler. Stuff specific to the ethernet audio device is marked ETH_AUD. */ int main() { int retval; int in_fd, out_fd; /* ETHAUD mmap the input and output buffers */ in_fd = open("/dev/eth_audio_in", O_RDONLY); out_fd = open("/dev/eth_audio_out", O_RDWR); assert(in_fd != -1); assert(out_fd != -1); in_buf = mmap(0, PGSIZE, PROT_READ, 0, in_fd, 0); if (in_buf == MAP_FAILED) { int err = errno; perror("Can't mmap the input buf:"); } out_buf = mmap(0, PGSIZE, PROT_READ | PROT_WRITE, MAP_POPULATE, out_fd, 0); if (out_buf == MAP_FAILED) { int err = errno; perror("Can't mmap the output buf:"); } //strncpy(out_buf, "Nanwan loves you!\n", 19); /* begin: stuff userspace needs to do before switching to multi-mode */ vcore_init(); /* ETHAUD Turn on Free apple pie (which is the network packet) */ enable_kevent(EV_FREE_APPLE_PIE, 0, EVENT_IPI); /* Need to save this somewhere that you can find it again when restarting * core0 */ core0_tls = get_tls_desc(0); /* Need to save our floating point state somewhere (like in the * user_thread_tcb so it can be restarted too */ /* end: stuff userspace needs to do before switching to multi-mode */ /* ETHAUD */ /* Switch into _M mode */ retval = vcore_request(1); /* Stay alive for a minute (will take interrupts) */ udelay(60000000); printf("Eth aud, finishing up!\n"); /* Need to do unmap it, due to some limitations in the kernel */ munmap(in_buf, PGSIZE); munmap(out_buf, PGSIZE); close(in_fd); close(out_fd); }
void ghetto_vcore_entry(void) { uint32_t vcoreid = vcore_id(); static bool first_time = TRUE; temp = 0xcafebabe; /* vcore_context test (don't need to do this anywhere) */ assert(in_vcore_context()); /* old logic was moved to parlib code */ if (current_uthread) { assert(vcoreid == 0); run_current_uthread(); } /* unmask notifications once you can let go of the uthread_ctx and it is * okay to clobber the transition stack. * Check Documentation/processes.txt: 4.2.4. In real code, you should be * popping the tf of whatever user process you want (get off the x-stack) */ enable_notifs(vcoreid); /* end: stuff userspace needs to do to handle notifications */ printf("Hello from vcore_entry in vcore %d with temp addr %p and temp %p\n", vcoreid, &temp, temp); #if 0 /* Test sys change vcore. Need to manually preempt the pcore vcore4 is * mapped to from the monitor */ udelay(20000000); if (vcoreid == 1) { disable_notifs(vcoreid); printf("VC1 changing to VC4\n"); sys_change_vcore(4, TRUE); /* try both of these manually */ //sys_change_vcore(4, FALSE); /* try both of these manually */ printf("VC1 returned\n"); } udelay(10000000); #endif vcore_request(1); //mcs_barrier_wait(&b,vcore_id()); udelay(vcoreid * 10000000); //exit(0); while(1); }
int main(int argc, char** argv) { /* don't forget to enable notifs on vcore0. if you don't, the kernel will * restart your _S with notifs disabled, which is a path to confusion. */ struct preempt_data *vcpd = &__procdata.vcore_preempt_data[0]; vcpd->notif_enabled = TRUE; mcs_barrier_init(&b, max_vcores()); vcore_request(max_vcores()); printf("not enough vcores, going to try it manually\n"); sys_resource_req(RES_CORES, max_vcores(), 1, REQ_SOFT); printf("We're screwed!\n"); /* should never make it here */ return -1; }
/** * Initialize the vcores, including jumping into muticore mode. **/ void vcore_startup() { /* Initilize the bootstrap code for using the vcores */ if (vcore_init()) printf("vcore_init() failed, we're f****d!\n"); assert(vcore_id() == 0); /* Tell the kernel where and how we want to receive events. This is just an * example of what to do to have a notification turned on. We're turning on * USER_IPIs, posting events to vcore 0's vcpd, and telling the kernel to * send to vcore 0. Note sys_self_notify will ignore the vcoreid pref. * Also note that enable_kevent() is just an example, and you probably want * to use parts of event.c to do what you want. */ enable_kevent(EV_USER_IPI, 0, EVENT_IPI); /* Don't forget to enable notifs on vcore0. if you don't, the kernel will * restart your _S with notifs disabled, which is a path to confusion. */ struct preempt_data *vcpd = &__procdata.vcore_preempt_data[0]; vcpd->notif_enabled = TRUE; /* Grab a reference to the main_thread on the current stack (i.e. * current_thread, since we know this has been set up for us properly by * the fact that the constructor calls main_thread_init() before this * function. We will need this reference below. */ thread_t *t = current_thread; /* Change temporarily to vcore0s tls region so we can save the main_thread * into its thread local current_thread variable. One minor issue is that * vcore0's transition-TLS isn't TLS_INITed yet. Until it is (right before * vcore_entry(), don't try and take the address of any of its TLS vars. */ extern void** vcore_thread_control_blocks; set_tls_desc(vcore_thread_control_blocks[0], 0); current_thread = t; set_tls_desc(t->context->tls_desc, 0); /* Jump into multi-core mode! */ /* The next line of code that will run is inside vcore_entry(). When this * thread is resumed, it will continue directly after this call to * vcore_request() */ vcore_request(1); }
int bthread_create(bthread_t* thread, const bthread_attr_t* attr, void *(*start_routine)(void *), void* arg) { struct mcs_lock_qnode local_qn = {0}; bthread_once(&init_once,&_bthread_init); *thread = (bthread_t)malloc(sizeof(work_queue_t)); (*thread)->start_routine = start_routine; (*thread)->arg = arg; (*thread)->next = 0; (*thread)->finished = 0; (*thread)->detached = 0; mcs_lock_lock(&work_queue_lock, &local_qn); { threads_active++; queue_insert(&work_queue_head,&work_queue_tail,*thread); // don't return until we get a vcore while(threads_active > num_vcores() && vcore_request(1)); } mcs_lock_unlock(&work_queue_lock, &local_qn); return 0; }
int main(int argc, char** argv) { uint32_t vcoreid; int retval; vcore_init(); if ((vcoreid = vcore_id())) { printf("Should never see me! (from vcore %d)\n", vcoreid); } else { // core 0 printf("Hello from else vcore 0\n"); printf("Multi-Goodbye, world, from PID: %d!\n", sys_getpid()); switch (test) { case TEST_MMAP: printf("Testing MMAP\n"); void *addr; addr = sys_mmap((void*)USTACKTOP - 20*PGSIZE, 8*PGSIZE, 3, MAP_FIXED | MAP_ANONYMOUS, -1, 0); printf("got addr = 0x%08x\n", addr); *(int*)addr = 0xdeadbeef; *(int*)(addr + 3*PGSIZE) = 0xcafebabe; // these should work printf("reading addr: 0x%08x\n", *(int*)addr); printf("reading addr+3pg: 0x%08x\n", *(int*)(addr + 3*PGSIZE)); // this should fault printf("Should page fault and die now.\n"); *(int*)(addr - 3*PGSIZE) = 0xdeadbeef; printf("Should not see me!!!!!!!!!!!!!!!!!!\n"); while(1); case TEST_ONE_CORE: retval = vcore_request(1); printf("One core test's core0's retval: %d\n", retval); printf("Check to see it's on a worker core.\n"); while(1); case TEST_ASK_FOR_TOO_MANY_CORES: retval = vcore_request(12); printf("Asked for too many, retval: %d\n", retval); return 0; case TEST_INCREMENTAL_CHANGES: retval = vcore_request(4); break; default: retval = vcore_request(5); } if (retval) panic("failed to allocate cores!"); printf("Should see me if you want to relocate core0's context " "when moving from RUNNING_S\n"); } // vcore0 only below here switch (test) { case TEST_YIELD_OUT_OF_ORDER: udelay(10000000); printf("Core 2 should have yielded, asking for another\n"); retval = vcore_request(5); break; case TEST_YIELD_0_OUT_OF_ORDER: udelay(5000000); printf("Core %d yielding\n", vcoreid); sys_yield(0); printf("Core 0 came back where it left off in RUNNING_M!!!\n"); break; } global_tests(vcoreid); printf("Vcore %d Done!\n", vcoreid); while (1); return 0; }
int main(int argc, char **argv) { int i, amt; int nr_gpcs = 1; uint64_t entry; int fd = open("#c/sysctl", O_RDWR), ret; int kfd = -1; bool smallkernel = false; void * x; static char cmd[512]; if (fd < 0) { perror("#c/sysctl"); exit(1); } argc--,argv++; if (argc != 2) { fprintf(stderr, "Usage: %s vmimage entrypoint\n", argv[0]); exit(1); } entry = strtoull(argv[1], 0, 0); kfd = open(argv[0], O_RDONLY); if (kfd < 0) { perror(argv[0]); exit(1); } if (ros_syscall(SYS_setup_vmm, nr_gpcs, 0, 0, 0, 0, 0) != nr_gpcs) { perror("Guest pcore setup failed"); exit(1); } my_threads = malloc(sizeof(pthread_t) * nr_threads); my_retvals = malloc(sizeof(void*) * nr_threads); if (!(my_retvals && my_threads)) perror("Init threads/malloc"); pthread_can_vcore_request(FALSE); /* 2LS won't manage vcores */ pthread_need_tls(FALSE); pthread_mcp_init(); /* gives us one vcore */ vcore_request(nr_threads - 1); /* ghetto incremental interface */ for (int i = 0; i < nr_threads; i++) { x = __procinfo.vcoremap; printf("%p\n", __procinfo.vcoremap); printf("Vcore %d mapped to pcore %d\n", i, __procinfo.vcoremap[i].pcoreid); } if (pthread_create(&my_threads[0], NULL, &talk_thread, NULL)) perror("pth_create failed"); // if (pthread_create(&my_threads[1], NULL, &fail, NULL)) // perror("pth_create failed"); printf("threads started\n"); if (0) for (int i = 0; i < nr_threads-1; i++) { int ret; if (pthread_join(my_threads[i], &my_retvals[i])) perror("pth_join failed"); printf("%d %d\n", i, ret); } ret = syscall(33, 1); if (ret < 0) { perror("vm setup"); exit(1); } /* blob that is faulted in from the EPT first. we need this to be in low * memory (not above the normal mmap_break), so the EPT can look it up. * Note that we won't get 4096. The min is 1MB now, and ld is there. */ mmap_blob = mmap((int*)(15*1048576), 16 * 1048576, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_ANONYMOUS, -1, 0); if (mmap_blob == MAP_FAILED) { perror("Unable to mmap"); exit(1); } memset(mmap_blob, 0, 16*1048576); // read in the kernel. x = mmap_blob + 0x1000000; for(;;) { amt = read(kfd, x, 1048576); if (amt < 0) { perror("read"); exit(1); } if (amt == 0) { break; } x += amt; } fprintf(stderr, "Read in %d bytes\n", x-mmap_blob); p512 = mmap_blob; p1 = &p512[512]; p2m = &p512[1024]; // We had thought to enter the kernel at the high address. But // there's just too much state the kernel has to clean up to // make this really work -- consider all the segment // descriptors that have to move, etc. So we will enter the // kernel in the low part of the address space, and let it // work up its page tables and the other good fun. Map the // kernel address space at low virtual, for 1G. It's ok to // map memory we have no access to. #define _2MiB 0x200000 p512[0] = (unsigned long long)p1 | 7; // if only we could guarantee 1G pages everywhere! p1[0] = /*0x87; */(unsigned long long)p2m | 7; for(i = 0; i < 16; i++) { p2m[i] = 0x87 | i * _2MiB; printf("pwm[%d] = 0x%llx\n", i, p2m[i]); } printf("p512 %p p512[0] is 0x%lx p1 %p p1[0] is 0x%x\n", p512, p512[0], p1, p1[0]); sprintf(cmd, "V 0x%llx 0x%llx 0x%llx", entry, (unsigned long long) &stack[1024], (unsigned long long) p512); printf("Writing command :%s:\n", cmd); ret = write(fd, cmd, strlen(cmd)); if (ret != strlen(cmd)) { perror(cmd); } sprintf(cmd, "V 0 0 0"); while (! done) { char c[1]; printf("hit return\n"); read(0, c, 1); if (debug) fprintf(stderr, "RESUME\n"); ret = write(fd, cmd, strlen(cmd)); if (ret != strlen(cmd)) { perror(cmd); } } return 0; }
int main(int argc, char** argv) { int num_started, retval; unsigned int ev_type; /* register our syscall handler (2LS does this) */ register_ev_handler(EV_SYSCALL, handle_syscall, 0); printf("Trying to block\n"); /* Not doing anything else to it: no EVENT_IPI yet, etc. */ ev_q = get_eventq(); /* issue the diagnostic block syscall */ sysc.num = SYS_block; sysc.arg0 = 5000; /* 5ms */ sysc.ev_q = ev_q; /* Trap */ num_started = __ros_arch_syscall((long)&sysc, 1); if (!(atomic_read(&sysc.flags) & SC_DONE)) printf("Not done, looping!\n"); /* You could poll on this. This is really ghetto, but i got rid of * event_activity, whose sole purpose was to encourage spinning. */ while (!(atomic_read(&sysc.flags) & SC_DONE)) cpu_relax(); handle_event_q(ev_q); /* by now, we should have run our handler */ /********************************************************/ /* Start MCP / IPI test */ printf("Switching to _M mode and testing an IPI-d ev_q\n"); printf("Our indirect ev_q is %08p\n", ev_q); /* begin: stuff userspace needs to do before switching to multi-mode */ /* Note we don't need to set up event reception for any particular kevent. * The ev_q in the syscall said to send an IPI to vcore 0 which means an * EV_EVENT will be sent straight to vcore0. */ /* Inits a thread for us, though we won't use it. Just a hack to get into * _M mode. Note this requests one vcore for us */ struct uthread dummy = {0}; uthread_2ls_init(&dummy, &ghetto_sched_ops); uthread_mcs_init(); /* Need to save our floating point state somewhere (like in the * user_thread_tcb so it can be restarted too */ enable_notifs(0); /* end: stuff userspace needs to do before switching to multi-mode */ retval = vcore_request(1); if (retval < 0) printf("No cores granted, Rut Ro Raggy!\n"); /* now we're back in thread 0 on vcore 0 */ ev_q->ev_flags = EVENT_IPI; ev_q->ev_vcore = 0; sysc.u_data = (void*)1; /* using this to loop on */ /* issue the diagnostic blocking syscall */ sysc.num = SYS_block; sysc.arg0 = 5000; /* 5ms */ sysc.ev_q = ev_q; num_started = __ros_arch_syscall((long)&sysc, 1); /* have this thread "wait" */ if (!(atomic_read(&sysc.flags) & SC_DONE)) printf("Not done, looping on a local variable!\n"); while (sysc.u_data) cpu_relax(); assert(atomic_read(&sysc.flags) & SC_DONE); printf("Syscall unblocked, IPI broke me out of the loop.\n"); /* done */ put_eventq(ev_q); printf("Syscall test exiting\n"); return 0; }
int main(int argc, char** argv) { uint32_t vcoreid; int retval; mcs_barrier_init(&b, max_vcores()); /* vcore_context test */ assert(!in_vcore_context()); /* prep indirect ev_q. Note we grab a big one */ indirect_q = get_big_event_q(); indirect_q->ev_flags = EVENT_IPI; indirect_q->ev_vcore = 1; /* IPI core 1 */ indirect_q->ev_handler = 0; printf("Registering %08p for event type %d\n", indirect_q, EV_FREE_APPLE_PIE); register_kevent_q(indirect_q, EV_FREE_APPLE_PIE); /* handle events: just want to print out what we get. This is just a * quick set of handlers, not a registration for a kevent. */ for (int i = 0; i < MAX_NR_EVENT; i++) ev_handlers[i] = handle_generic; /* Want to use the default ev_ev (which we just overwrote) */ ev_handlers[EV_EVENT] = handle_ev_ev; /* vcore_init() done in vcore_request() now. */ /* Set up event reception. For example, this will allow us to receive an * event and IPI for USER_IPIs on vcore 0. Check event.c for more stuff. * Note you don't have to register for USER_IPIs to receive ones you send * yourself with sys_self_notify(). */ enable_kevent(EV_USER_IPI, 0, EVENT_IPI); /* Receive pending preemption events. Can also get a MSG if you want. */ struct event_queue *ev_q = get_event_q(); ev_q->ev_flags = EVENT_IPI | EVENT_NOMSG | EVENT_VCORE_APPRO; register_kevent_q(ev_q, EV_PREEMPT_PENDING); /* Makes a thread for us, though we won't use it. Just a hack to get into * _M mode. Note this requests one vcore for us */ uthread_create(dummy, 0); if ((vcoreid = vcore_id())) { printf("Should never see me! (from vcore %d)\n", vcoreid); } else { // core 0 temp = 0xdeadbeef; printf("Hello from vcore %d with temp addr = %p and temp = %p\n", vcoreid, &temp, temp); printf("Multi-Goodbye, world, from PID: %d!\n", sys_getpid()); //retval = sys_resource_req(RES_CORES, 2, 0); printf("Requesting %d vcores\n", max_vcores() - 1); retval = vcore_request(max_vcores() - 1); /* since we already have 1 */ //retval = vcore_request(5); printf("This is vcore0, right after vcore_request, retval=%d\n", retval); /* vcore_context test */ assert(!in_vcore_context()); } /* test notifying my vcore2 */ udelay(5000000); printf("Vcore 0 self-notifying vcore 2 with notif 4!\n"); struct event_msg msg; msg.ev_type = 4; sys_self_notify(2, 4, &msg); udelay(5000000); printf("Vcore 0 notifying itself with notif 3!\n"); msg.ev_type = 3; sys_notify(sys_getpid(), 3, &msg); udelay(1000000); /* test loop for restarting a notif_tf */ if (vcoreid == 0) { int ctr = 0; while(1) { printf("Vcore %d Spinning (%d), temp = %08x!\n", vcoreid, ctr++, temp); udelay(5000000); //exit(0); } } printf("Vcore %d Done!\n", vcoreid); //mcs_barrier_wait(&b,vcore_id()); printf("All Cores Done!\n", vcoreid); while(1); // manually kill from the monitor return 0; }
/* to trick uthread_create() */ int main(int argc, char** argv) { uint32_t vcoreid; int retval; /* Initialize our barrier. */ mcs_barrier_init(&b, max_vcores()); /* vcore_context test */ assert(!in_vcore_context()); /* prep indirect ev_q. Note we grab a big one */ indirect_q = get_eventq(EV_MBOX_UCQ); indirect_q->ev_flags = EVENT_IPI; indirect_q->ev_vcore = 1; /* IPI core 1 */ indirect_q->ev_handler = 0; printf("Registering %08p for event type %d\n", indirect_q, EV_FREE_APPLE_PIE); register_kevent_q(indirect_q, EV_FREE_APPLE_PIE); /* handle events: just want to print out what we get. This is just a * quick set of handlers, not a registration for a kevent. */ for (int i = 0; i < MAX_NR_EVENT; i++) register_ev_handler(i, handle_generic, 0); /* Want to use the default ev_ev (which we just overwrote) */ register_ev_handler(EV_EVENT, handle_ev_ev, 0); /* vcore_lib_init() done in vcore_request() now. */ /* Set up event reception. For example, this will allow us to receive an * event and IPI for USER_IPIs on vcore 0. Check event.c for more stuff. * Note you don't have to register for USER_IPIs to receive ones you send * yourself with sys_self_notify(). */ enable_kevent(EV_USER_IPI, 0, EVENT_IPI | EVENT_VCORE_PRIVATE); /* Receive pending preemption events. (though there's no PP handler) */ struct event_queue *ev_q = get_eventq_vcpd(0, EVENT_VCORE_PRIVATE); ev_q->ev_flags = EVENT_IPI | EVENT_VCORE_APPRO; register_kevent_q(ev_q, EV_PREEMPT_PENDING); /* We also receive preemption events, it is set up in uthread.c */ /* Inits a thread for us, though we won't use it. Just a hack to get into * _M mode. Note this requests one vcore for us */ struct uthread dummy = {0}; uthread_2ls_init(&dummy, &ghetto_sched_ops); uthread_mcp_init(); /* Reset the blockon to be the spinner... This is really shitty. Any * blocking calls after we become an MCP and before this will fail. This is * just mhello showing its warts due to trying to work outside uthread.c */ ros_syscall_blockon = __ros_syscall_spinon; if ((vcoreid = vcore_id())) { printf("Should never see me! (from vcore %d)\n", vcoreid); } else { // core 0 temp = 0xdeadbeef; printf("Hello from vcore %d with temp addr = %p and temp = %p\n", vcoreid, &temp, temp); printf("Multi-Goodbye, world, from PID: %d!\n", sys_getpid()); printf("Requesting %d vcores\n", max_vcores() - 1); retval = vcore_request(max_vcores() - 1); /* since we already have 1 */ //retval = vcore_request(5); printf("This is vcore0, right after vcore_request, retval=%d\n", retval); /* vcore_context test */ assert(!in_vcore_context()); } //#if 0 /* test notifying my vcore2 */ udelay(5000000); printf("Vcore 0 self-notifying vcore 2 with notif 4!\n"); struct event_msg msg; msg.ev_type = 4; sys_self_notify(2, 4, &msg, TRUE); udelay(5000000); printf("Vcore 0 notifying itself with notif 6!\n"); msg.ev_type = 6; sys_notify(sys_getpid(), 6, &msg); udelay(1000000); //#endif /* test loop for restarting a uthread_ctx */ if (vcoreid == 0) { int ctr = 0; while(1) { printf("Vcore %d Spinning (%d), temp = %08x!\n", vcoreid, ctr++, temp); udelay(5000000); //exit(0); } } printf("Vcore %d Done!\n", vcoreid); //mcs_barrier_wait(&b,vcore_id()); printf("All Cores Done!\n", vcoreid); while(1); // manually kill from the monitor /* since everyone should cleanup their uthreads, even if they don't plan on * calling their code or want uthreads in the first place. <3 */ uthread_cleanup(&dummy); return 0; }