Removed event overflow handling
[akaros.git] / tests / syscall.c
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <parlib.h>
4 #include <event.h>
5 #include <vcore.h>
6 #include <rassert.h>
7 #include <ros/bcq.h>
8 #include <uthread.h>
9
10 static void handle_syscall(struct event_msg *ev_msg, unsigned int ev_type);
11 struct syscall sysc = {0};
12 struct event_queue *ev_q;
13 void *core0_tls = 0;
14
15 void ghetto_vcore_entry(void);
16 struct uthread *ghetto_init(void)
17 {
18         return malloc(sizeof(struct uthread));
19 }
20
21 struct schedule_ops ghetto_sched_ops = {
22         .sched_init = ghetto_init,
23         .sched_entry = ghetto_vcore_entry,
24 };
25 struct schedule_ops *sched_ops = &ghetto_sched_ops;
26
27 int main(int argc, char** argv)
28 {
29         int num_started, retval;
30         unsigned int ev_type;
31
32         /* register our syscall handler (2LS does this) */
33         ev_handlers[EV_SYSCALL] = handle_syscall;
34
35         printf("Trying to block\n");
36         /* Not doing anything else to it: no EVENT_IPI yet, etc. */
37         ev_q = get_big_event_q();
38         /* issue the diagnostic block syscall */
39         sysc.num = SYS_block;
40         sysc.arg0 = 5000;       /* 5ms */
41         sysc.ev_q = ev_q;
42         /* Trap */
43         num_started = __ros_arch_syscall((long)&sysc, 1);
44         if (!(atomic_read(&sysc.flags) & SC_DONE))
45                 printf("Not done, looping!\n");
46         /* You could poll on this.  This is really ghetto, but i got rid of
47          * event_activity, whose sole purpose was to encourage spinning. */
48         while (!(atomic_read(&sysc.flags) & SC_DONE))
49                 cpu_relax();
50         handle_event_q(ev_q);
51         /* by now, we should have run our handler */
52         /********************************************************/
53         /* Start MCP / IPI test */
54         printf("Switching to _M mode and testing an IPI-d ev_q\n");
55         printf("Our indirect ev_q is %08p\n", ev_q);
56
57 /* begin: stuff userspace needs to do before switching to multi-mode */
58         /* Note we don't need to set up event reception for any particular kevent.
59          * The ev_q in the syscall said to send an IPI to vcore 0 which means an
60          * EV_EVENT will be sent straight to vcore0. */
61         /* Need to save this somewhere that you can find it again when restarting
62          * core0 */
63         core0_tls = get_tls_desc(0);
64         /* Need to save our floating point state somewhere (like in the
65          * user_thread_tcb so it can be restarted too */
66         enable_notifs(0);
67 /* end: stuff userspace needs to do before switching to multi-mode */
68
69         retval = vcore_request(1);
70         if (retval < 0)
71                 printf("No cores granted, Rut Ro Raggy!\n");
72         /* now we're back in thread 0 on vcore 0 */
73         ev_q->ev_flags = EVENT_IPI;
74         ev_q->ev_vcore = 0;
75         sysc.u_data = (void*)1; /* using this to loop on */
76         /* issue the diagnostic blocking syscall */
77         sysc.num = SYS_block;
78         sysc.arg0 = 5000;       /* 5ms */
79         sysc.ev_q = ev_q;
80         num_started = __ros_arch_syscall((long)&sysc, 1);
81         /* have this thread "wait" */
82         if (!(atomic_read(&sysc.flags) & SC_DONE))
83                 printf("Not done, looping on a local variable!\n");
84         while (sysc.u_data)
85                 cpu_relax();
86         assert(atomic_read(&sysc.flags) & SC_DONE);
87         printf("Syscall unblocked, IPI broke me out of the loop.\n");
88
89         /* done */
90         put_big_event_q(ev_q);
91         printf("Syscall test exiting\n");
92         return 0;
93 }
94
95 static void handle_syscall(struct event_msg *ev_msg, unsigned int ev_type)
96 {
97         struct syscall *my_sysc;
98         if (!ev_msg)
99                 return;
100         my_sysc = ev_msg->ev_arg3;
101         printf("Handling syscall event for sysc %08p (%08p)\n",
102                my_sysc, &sysc);
103         /* our syscall should be done (we ought to check the msg pointer) */
104         if (atomic_read(&sysc.flags) & SC_DONE) 
105                 printf("Syscall is done, retval: %d\n", sysc.retval);
106         else
107                 printf("BUG! Syscall wasn't done!\n");
108         /* signal to thread 0 that the sysc is done, just to show this
109          * is getting done in vcore context. */
110         my_sysc->u_data = 0;
111 }
112
113 void ghetto_vcore_entry(void)
114 {
115         uint32_t vcoreid = vcore_id();
116         static bool first_time = TRUE;
117
118 /* begin: stuff userspace needs to do to handle notifications */
119
120         /* Restart vcore0's context. */
121         if (vcoreid == 0) {
122                 run_current_uthread();
123                 panic("should never see me!");
124         }       
125         /* unmask notifications once you can let go of the notif_tf and it is okay
126          * to clobber the transition stack.
127          * Check Documentation/processes.txt: 4.2.4.  In real code, you should be
128          * popping the tf of whatever user process you want (get off the x-stack) */
129         struct preempt_data *vcpd;
130         vcpd = &__procdata.vcore_preempt_data[vcoreid];
131         vcpd->notif_enabled = TRUE;
132         
133 /* end: stuff userspace needs to do to handle notifications */
134         /* if you have other vcores, they'll just chill here */
135         while(1);
136 }