605eb2ded9d4d569f478244bc76f05827e6908e2
[cilux] / src / platform / linux / kernelplat.c
1
2 /* -------------------------------------------------------------------------- */
3
4 static fd_set rd_fd_set;
5 static fd_set wr_fd_set;
6 static fd_set ex_fd_set;
7
8 /* -------------------------------------------------------------------------- */
9
10 static void signal_terminate(int);
11 static void signal_alarm(int);
12 static void signal_other(int);
13 static void set_timeval_ms(struct timeval* t, int ms);
14
15 /* -------------------------------------------------------------------------- */
16
17 static Window        x11Window   = 0;
18 static Display*      x11Display  = 0;
19 static long          x11Screen   = 0;
20 static XVisualInfo*  x11Visual   = 0;
21 static Colormap      x11Colormap = 0;
22  
23 static EGLNativeDisplayType eglX11Display = 0;
24 static EGLNativeWindowType  eglX11Window  = 0;
25 static EGLDisplay           eglDisplay    = 0;
26 static EGLConfig            eglConfig     = 0;
27 static EGLSurface           eglSurface    = 0;
28 static EGLContext           eglContext    = 0;
29
30 /* -------------------------------------------------------------------------- */
31
32 static int create_gl_window();
33 static int getX11Display(int windowwidth, int windowheight);
34 static int setUpEGL();
35 static void checkX11Events();
36
37 /* -------------------------------------------------------------------------- */
38
39 void init_thread(void)
40 {
41     signal(SIGTERM, signal_terminate);
42     signal(SIGINT,  signal_terminate);
43     signal(SIGQUIT, signal_terminate);
44     signal(SIGALRM, signal_alarm);
45     signal(SIGPIPE, signal_other);
46     signal(SIGCHLD, SIG_IGN);
47     signal(SIGHUP,  SIG_IGN);
48     signal(SIGUSR1, SIG_IGN);
49     signal(SIGUSR2, SIG_IGN);
50 }
51
52 void init_net(void)
53 {
54     FD_ZERO(&rd_fd_set);
55     FD_ZERO(&wr_fd_set);
56     FD_ZERO(&ex_fd_set);
57 }
58
59 void init_gl(void)
60 {
61     create_gl_window();
62 }
63
64 /* -------------------------------------------------------------------------- */
65
66 OTHER_THREAD void signal_terminate(int signum)
67 {
68     c_running(0);
69 }
70
71 OTHER_THREAD void signal_alarm(int signum)
72 {
73     c_signal(signum);
74 }
75
76 OTHER_THREAD void signal_other(int signum)
77 {
78     c_signal(signum);
79 }
80
81 /* -------------------------------------------------------------------------- */
82
83 void set_callback(k_channel* chan, int rdwr)
84 {
85     if(rdwr & SETCB_RD) FD_SET(chan->priv->SOCK, &rd_fd_set);
86     if(rdwr & SETCB_WR) FD_SET(chan->priv->SOCK, &wr_fd_set);
87 }
88
89 void un_set_callback(k_channel* chan, int rdwr)
90 {
91     if(rdwr & SETCB_RD) FD_CLR(chan->priv->SOCK, &rd_fd_set);
92     if(rdwr & SETCB_WR) FD_CLR(chan->priv->SOCK, &wr_fd_set);
93 }
94
95 void poller(int no_block)
96 {
97     fd_set rd=rd_fd_set;
98     fd_set wr=wr_fd_set;
99     fd_set ex=ex_fd_set;
100
101     k_channel* chan;
102
103     int highest=0;
104     for(chan=k_channels; chan; chan=chan->next){
105         if(chan->priv->state==CHAN_CLOSE) continue;
106         if(highest < chan->priv->SOCK) highest=chan->priv->SOCK;
107     }
108
109     struct timeval  t;
110     struct timeval* tp=&t;
111     set_timeval_ms(tp, no_block? 0: LOOP_TICK);
112
113     if(highest==0){
114         select(0, 0, 0, 0, tp);
115         next_keys();
116         if(!no_block) do_regular_things();
117         return;
118     }
119
120     int len=select(highest+1, &rd, &wr, &ex, tp);
121     GETERRNO(len);
122
123     checkX11Events();
124     next_keys();
125
126     if(len==0){
127         do_regular_things();
128         return;
129     }
130     if(len== -1){
131         if(ERRNO==INTERRUPTED) return;
132         log_net_err("select", ERRNO);
133         sleep(1);
134         do_regular_things();
135         return;
136     }
137
138     for(chan=k_channels; chan; chan=chan->next){
139         if(FD_ISSET(chan->priv->SOCK, &ex)){
140             exception_socket(chan);
141             continue;
142         }
143         if(FD_ISSET(chan->priv->SOCK, &wr)){
144             int err; socklen_t len=sizeof(int);
145             if(getsockopt(chan->priv->SOCK,
146                           SOL_SOCKET,
147                           SO_ERROR, &err, &len) || err){
148                 exception_socket(chan);
149                 continue;
150             }
151             else{
152                 writeable_socket(chan);
153             }
154         }
155         if(FD_ISSET(chan->priv->SOCK, &rd)){
156             readable_socket(chan);
157         }
158     }
159 }
160
161 void set_timeval_ms(struct timeval* t, int ms)
162 {
163     t->tv_sec=ms/1000;
164     t->tv_usec=(ms-(t->tv_sec)*1000)*1000;
165 }
166
167 char* str_error(int e)
168 {
169     return strerror(e);
170 }
171
172 /* -------------------------------------------------------------------------- */
173
174 void stat_only(char* fullname, k_stat* kstat)
175 {
176     kstat->type=0;
177     struct stat s;
178     if(stat(fullname, &s)) return;
179     kstat->type=s.st_mode & 0170000;
180     kstat->size=s.st_size;
181     kstat->time=s.st_mtime;
182     kstat->perm=s.st_mode & 0007777;
183 }
184
185 FILE_T stat_open(char* fullname, k_stat* kstat)
186 {
187     stat_only(fullname, kstat);
188     if(!kstat->type) return 0;
189     FILE_T filehandle=open(fullname, O_RDONLY);
190     if(filehandle<0) return 0;
191     return filehandle;
192 }
193
194 FILE_T open_only(char* fullname, int wr)
195 {
196     int rw=wr? O_RDWR|O_CREAT|O_TRUNC: O_RDONLY;
197     FILE_T filehandle=open(fullname, rw, 0644);
198     if(filehandle<0) return 0;
199     return filehandle;
200 }
201
202 void* mmap_malloc(void* s, size_t size, int prot, int f, char* fullname, int o)
203 {
204     FILE_T fh=open(fullname, O_RDONLY, 0644);
205     if(fh<0) return MAP_FAILED;
206
207     char* data=k_malloc(size);
208     int charsread=0;
209     int len;
210     do{
211         len=read(fh, data+charsread, size-charsread);
212         if(len< 0 && FERRNO(len)==EINTR) continue;
213         if(len<=0) break;
214         charsread+=len;
215     } while(charsread<size);
216
217     close(fh);
218     if(len<0 || charsread!=size){ k_free(data); return MAP_FAILED; }
219     return data;
220 }
221
222 void* mmap_name(void* s, size_t size, int prot, int f, char* fullname, int o)
223 {
224     if(!size) return MAP_FAILED;
225     int w=(prot & PROT_WRITE);
226     FILE_T fh=open(fullname, (w? O_RDWR|O_CREAT: O_RDONLY), 0644);
227     if(fh<0) return MAP_FAILED;
228     return mmap(s, size, prot, f, fh, o);
229 }
230
231 /* -------------------------------------------------------------------------- */
232
233 EXPORT void k_random_bytes(char* buf, size_t size)
234 {
235     *(short*)buf=getpid();
236     if(size!=2) k_log_err("Linux randomness not implemented yet!");
237 }
238
239 /* -------------------------------------------------------------------------- */
240
241 EXPORT void* k_malloc(size_t size)
242 {
243     void* p=malloc(size);
244     if(!p){
245         k_fatal(OOM_STRING);
246     }
247     return p;
248 }
249
250 EXPORT void* k_realloc(void* o, size_t size)
251 {
252     void* p=realloc(o, size);
253     if(!p){
254         k_fatal(OOM_STRING);
255     }
256     return p;
257 }
258
259 EXPORT void k_free(void* o)
260 {
261     if(o) free(o);
262 }
263
264 EXPORT char* k_strdup(char* s)
265 {
266     if(!s) return 0;
267     char* p=strdup(s);
268     if(!p){
269         k_fatal(OOM_STRING);
270     }
271     return p;
272 }
273
274 EXPORT void* k_memdup(void* s, size_t size)
275 {
276     void* p=malloc(size);
277     if(!p){
278         k_fatal(OOM_STRING);
279     }
280     memcpy(p, s, size);
281     return p;
282 }
283
284 /* ------------------------------------------------------------- */
285
286 #define WINDOW_WIDTH  640
287 #define WINDOW_HEIGHT 480
288
289 int create_gl_window()
290 {
291     if(!getX11Display(WINDOW_WIDTH, WINDOW_HEIGHT)) return 0;
292     if(!setUpEGL())                                 return 0;
293     return 1;
294 }
295
296 /* ------------------------------------------------------------- */
297
298 int getX11Display(int windowwidth, int windowheight)
299 {
300     x11Display = XOpenDisplay(0);
301
302     if(!x11Display) {
303         printf("Error: Unable to open X display\n");
304         return 0;
305     }
306
307     x11Screen = XDefaultScreen(x11Display);
308     Window rootWindow = RootWindow(x11Display, x11Screen);
309     int depth = DefaultDepth(x11Display, x11Screen);
310     x11Visual = malloc(sizeof(XVisualInfo));
311     XMatchVisualInfo(x11Display, x11Screen, depth, TrueColor, x11Visual);
312
313     if(!x11Visual) {
314         printf("Error: Unable to acquire visual\n");
315         return 0;
316     }
317
318     x11Colormap = XCreateColormap(x11Display, rootWindow, x11Visual->visual, AllocNone);
319     XSetWindowAttributes XSWA;
320     XSWA.colormap = x11Colormap;
321     XSWA.event_mask = StructureNotifyMask | ExposureMask |
322                       ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask;
323     unsigned int cwmask = CWBackPixel | CWBorderPixel | CWEventMask | CWColormap;
324
325     x11Window = XCreateWindow(x11Display, RootWindow(x11Display, x11Screen), 0, 0, windowwidth, windowheight,
326                               0, CopyFromParent, InputOutput, CopyFromParent, cwmask, &XSWA);
327     XMapWindow(x11Display, x11Window);
328     XFlush(x11Display);
329
330     eglX11Display = (EGLNativeDisplayType)x11Display;
331     eglX11Window  = (EGLNativeWindowType) x11Window;
332
333     return 1;
334 }
335
336 void cleanupX11()
337 {
338     if(x11Window)   XDestroyWindow(x11Display, x11Window);
339     if(x11Colormap) XFreeColormap( x11Display, x11Colormap);
340     if(x11Display)  XCloseDisplay( x11Display);
341 }
342
343 void checkX11Events()
344 {
345     int nm = XPending(x11Display);
346     int m;
347     for(m=0; m< nm; m++) {
348         XEvent event;
349         XNextEvent(x11Display, &event);
350         switch(event.type){
351             case ButtonPress:
352             break;
353             case KeyPress:
354                 c_key((unsigned char)event.xkey.keycode, 1);
355             break;
356             default:
357             break;
358         }
359     }
360 }
361
362 /* -------------------------------------------------------------------------- */
363
364 int isEGLError(char* where)
365 {
366     EGLint err = eglGetError();
367     if(err != EGL_SUCCESS) {
368         printf("EGL failed at %s (%d).\n", where, err);
369         return 1;
370     }
371     return 0;
372 }
373
374 int setUpEGL()
375 {
376     eglDisplay = eglGetDisplay(eglX11Display);
377
378     EGLint iMajorVersion, iMinorVersion;
379     if(!eglInitialize(eglDisplay, &iMajorVersion, &iMinorVersion)) {
380         printf("Error: eglInitialize() failed.\n");
381         return 0;
382     }
383
384     EGLint pi32ConfigAttribs[5];
385     pi32ConfigAttribs[0] = EGL_SURFACE_TYPE;
386     pi32ConfigAttribs[1] = EGL_WINDOW_BIT;
387     pi32ConfigAttribs[2] = EGL_RENDERABLE_TYPE;
388     pi32ConfigAttribs[3] = EGL_OPENGL_ES2_BIT;    
389     pi32ConfigAttribs[4] = EGL_NONE;
390
391     EGLint pi32ContextAttribs[3];
392     pi32ContextAttribs[0] = EGL_CONTEXT_CLIENT_VERSION;
393     pi32ContextAttribs[1] = 2;
394     pi32ContextAttribs[2] = EGL_NONE;
395
396     int iConfigs;
397     if(!eglChooseConfig(eglDisplay, pi32ConfigAttribs, &eglConfig, 1, &iConfigs) || (iConfigs != 1)) {
398         printf("Error: eglChooseConfig() failed.\n");
399         return 0;
400     }
401
402     eglSurface = eglCreateWindowSurface(eglDisplay, eglConfig, eglX11Window, NULL);
403     if(isEGLError("eglCreateWindowSurface")) return 0;
404
405     eglContext = eglCreateContext(eglDisplay, eglConfig, NULL, pi32ContextAttribs);
406     if(isEGLError("eglCreateContext")) return 0;
407
408     eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext);
409     if(isEGLError("eglMakeCurrent")) return 0;
410
411     return 1;
412 }
413
414 /* -------------------------------------------------------------------------- */
415
416 EXPORT void k_gl_swap_buffers(void)
417 {
418     eglSwapBuffers(eglDisplay, eglSurface);
419 }
420
421 EXPORT void k_gl_end(void)
422 {
423     eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
424     eglTerminate(eglDisplay);
425 }
426
427 /* -------------------------------------------------------------------------- */
428