| #include <stdlib.h> | 
 | #include <stdio.h> | 
 | #include <parlib.h> | 
 | #include <event.h> | 
 | #include <vcore.h> | 
 | #include <rassert.h> | 
 | #include <ros/bcq.h> | 
 | #include <uthread.h> | 
 |  | 
 | /* Deprecated, don't use this in any serious way */ | 
 |  | 
 | static void handle_syscall(struct event_msg *ev_msg, unsigned int ev_type, | 
 |                            void *data); | 
 | struct syscall sysc = {0}; | 
 | struct event_queue *ev_q; | 
 | void ghetto_vcore_entry(void); | 
 |  | 
 | struct schedule_ops ghetto_sched_ops = { | 
 | 	.sched_entry = ghetto_vcore_entry, | 
 | }; | 
 | struct schedule_ops *sched_ops = &ghetto_sched_ops; | 
 |  | 
 | 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_big_event_q(); | 
 | 	/* 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_lib_init(&dummy); | 
 | 	/* 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_big_event_q(ev_q); | 
 | 	printf("Syscall test exiting\n"); | 
 | 	return 0; | 
 | } | 
 |  | 
 | static void handle_syscall(struct event_msg *ev_msg, unsigned int ev_type, | 
 |                            void *data) | 
 | { | 
 | 	struct syscall *my_sysc; | 
 | 	if (!ev_msg) | 
 | 		return; | 
 | 	my_sysc = ev_msg->ev_arg3; | 
 | 	printf("Handling syscall event for sysc %08p (%08p)\n", | 
 | 	       my_sysc, &sysc); | 
 | 	/* our syscall should be done (we ought to check the msg pointer) */ | 
 | 	if (atomic_read(&sysc.flags) & SC_DONE)  | 
 | 		printf("Syscall is done, retval: %d\n", sysc.retval); | 
 | 	else | 
 | 		printf("BUG! Syscall wasn't done!\n"); | 
 | 	/* signal to thread 0 that the sysc is done, just to show this | 
 | 	 * is getting done in vcore context. */ | 
 | 	my_sysc->u_data = 0; | 
 | } | 
 |  | 
 | void ghetto_vcore_entry(void) | 
 | { | 
 | 	uint32_t vcoreid = vcore_id(); | 
 | 	static bool first_time = TRUE; | 
 |  | 
 | /* begin: stuff userspace needs to do to handle notifications */ | 
 |  | 
 | 	/* Restart vcore0's context. */ | 
 | 	if (vcoreid == 0) { | 
 | 		run_current_uthread(); | 
 | 		panic("should never see me!"); | 
 | 	}	 | 
 | 	/* 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) */ | 
 | 	struct preempt_data *vcpd; | 
 | 	vcpd = &__procdata.vcore_preempt_data[vcoreid]; | 
 | 	vcpd->notif_disabled = FALSE; | 
 | 	 | 
 | /* end: stuff userspace needs to do to handle notifications */ | 
 | 	/* if you have other vcores, they'll just chill here */ | 
 | 	while(1); | 
 | } |