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