1
+ #include <features.h>
1
2
#include <dlfcn.h>
2
3
#include <fcntl.h>
3
4
#include <stdio.h>
10
11
#include <EGL/eglext.h>
11
12
#include <GLES/gl.h>
12
13
#include <linux/input.h>
14
+ #include <pthread.h>
15
+ #include <signal.h>
16
+ #include <errno.h>
13
17
14
18
#include <math.h>
15
19
#include <limits.h>
20
24
#include "flutter-pi.h"
21
25
#include "methodchannel.h"
22
26
23
- #define PATH_EXISTS (path ) (access((path),R_OK)==0)
24
-
25
27
26
28
char * usage = "Flutter Raspberry Pi\n\nUsage:\n flutter-pi <asset_bundle_path> <flutter_flags>\n" ;
27
29
@@ -47,26 +49,34 @@ double mouse_x = 0;
47
49
double mouse_y = 0 ;
48
50
uint8_t button = 0 ;
49
51
52
+ pthread_t io_thread_id ;
53
+ pthread_t platform_thread_id ;
54
+ struct LinkedTaskListElement task_list_head_sentinel
55
+ = {.next = NULL , .target_time = 0 , .task = {.runner = NULL , .task = 0 }};
56
+ pthread_mutex_t task_list_lock ;
57
+ bool should_notify_platform_thread = false;
58
+ sigset_t sigusr1_set ;
59
+
50
60
/*********************
51
61
* FLUTTER CALLBACKS *
52
62
*********************/
53
- bool make_current (void * userdata ) {
63
+ bool make_current (void * userdata ) {
54
64
if (eglMakeCurrent (display , surface , surface , context ) != EGL_TRUE ) {
55
65
fprintf (stderr , "Could not make the context current.\n" );
56
66
return false;
57
67
}
58
68
59
69
return true;
60
70
}
61
- bool clear_current (void * userdata ) {
71
+ bool clear_current (void * userdata ) {
62
72
if (eglMakeCurrent (display , EGL_NO_SURFACE , EGL_NO_SURFACE , EGL_NO_CONTEXT ) != EGL_TRUE ) {
63
73
fprintf (stderr , "Could not clear the current context.\n" );
64
74
return false;
65
75
}
66
76
67
77
return true;
68
78
}
69
- bool present (void * userdata ) {
79
+ bool present (void * userdata ) {
70
80
if (eglSwapBuffers (display , surface ) != EGL_TRUE ) {
71
81
fprintf (stderr , "Could not swap buffers to present the screen.\n" );
72
82
return false;
@@ -82,7 +92,7 @@ bool present(void* userdata) {
82
92
uint32_t fbo_callback (void * userdata ) {
83
93
return 0 ;
84
94
}
85
- void * proc_resolver (void * userdata , const char * name ) {
95
+ void * proc_resolver (void * userdata , const char * name ) {
86
96
if (name == NULL ) return NULL ;
87
97
88
98
printf ("calling proc_resolver with %s\n" , name );
@@ -94,23 +104,118 @@ void* proc_resolver(void* userdata, const char* name) {
94
104
95
105
return NULL ;
96
106
}
97
- void on_platform_message (const FlutterPlatformMessage * message , void * userdata ) {
98
- printf ("Got Platform Message on Channel: %s\n" , message -> channel );
99
-
107
+ void on_platform_message (const FlutterPlatformMessage * message , void * userdata ) {
100
108
struct MethodCall methodcall ;
101
109
if (!MethodChannel_decode (message -> message_size , (uint8_t * ) (message -> message ), & methodcall )) {
102
110
fprintf (stderr , "Decoding method call failed\n" );
103
111
return ;
104
112
}
105
113
printf ("MethodCall: method name: %s argument type: %d\n" , methodcall .method , methodcall .argument .type );
106
114
115
+ if (strcmp (methodcall .method , "counter" ) == 0 ) {
116
+ printf ("method \"counter\" was called with argument %d\n" , methodcall .argument .value .int_value );
117
+ }
118
+
107
119
MethodChannel_freeMethodCall (& methodcall );
108
120
}
109
121
122
+ /************************
123
+ * PLATFORM TASK-RUNNER *
124
+ ************************/
125
+ void handle_signal (int _ ) {}
126
+ bool init_message_loop () {
127
+ platform_thread_id = pthread_self ();
128
+
129
+ // first, initialize the task heap mutex
130
+ if (pthread_mutex_init (& task_list_lock , NULL ) != 0 ) {
131
+ fprintf (stderr , "Could not initialize task list mutex\n" );
132
+ return false;
133
+ }
134
+
135
+ sigemptyset (& sigusr1_set );
136
+ sigaddset (& sigusr1_set , SIGUSR1 );
137
+
138
+ sigaction (SIGUSR1 , & (struct sigaction ) {.sa_handler = & handle_signal }, NULL );
139
+ pthread_sigmask (SIG_UNBLOCK , & sigusr1_set , NULL );
140
+
141
+ return true;
142
+ }
143
+ bool message_loop (void ) {
144
+ should_notify_platform_thread = true;
145
+
146
+ while (true) {
147
+ pthread_mutex_lock (& task_list_lock );
148
+ if (task_list_head_sentinel .next == NULL ) {
149
+ pthread_mutex_unlock (& task_list_lock );
150
+
151
+ sigwaitinfo (& sigusr1_set , NULL );
152
+ } else {
153
+ uint64_t target_time = task_list_head_sentinel .next -> target_time ;
154
+ uint64_t current_time = FlutterEngineGetCurrentTime ();
155
+
156
+ if (target_time > current_time ) {
157
+ uint64_t diff = target_time - current_time ;
158
+
159
+ struct timespec target_timespec = {
160
+ .tv_sec = (uint64_t ) (diff / 1000000000l ),
161
+ .tv_nsec = (uint64_t ) (diff % 1000000000l )
162
+ };
163
+
164
+ pthread_mutex_unlock (& task_list_lock );
165
+
166
+ int result = sigtimedwait (& sigusr1_set , NULL , & target_timespec );
167
+ if (result == EINTR ) continue ;
168
+ } else {
169
+ pthread_mutex_unlock (& task_list_lock );
170
+ }
171
+ }
172
+
173
+ pthread_mutex_lock (& task_list_lock );
174
+ FlutterTask task = task_list_head_sentinel .next -> task ;
175
+
176
+ struct LinkedTaskListElement * new_first = task_list_head_sentinel .next -> next ;
177
+ free (task_list_head_sentinel .next );
178
+ task_list_head_sentinel .next = new_first ;
179
+ pthread_mutex_unlock (& task_list_lock );
180
+
181
+ if (FlutterEngineRunTask (engine , & task ) != kSuccess ) {
182
+ fprintf (stderr , "Error running platform task\n" );
183
+ return false;
184
+ };
185
+ }
186
+
187
+ return true;
188
+ }
189
+ void post_platform_task (FlutterTask task , uint64_t target_time , void * userdata ) {
190
+ struct LinkedTaskListElement * to_insert = malloc (sizeof (struct LinkedTaskListElement ));
191
+ to_insert -> next = NULL ;
192
+ to_insert -> task = task ;
193
+ to_insert -> target_time = target_time ;
194
+
195
+ pthread_mutex_lock (& task_list_lock );
196
+ struct LinkedTaskListElement * this = & task_list_head_sentinel ;
197
+ while ((this -> next ) != NULL && (target_time > this -> next -> target_time ))
198
+ this = this -> next ;
199
+
200
+ to_insert -> next = this -> next ;
201
+ this -> next = to_insert ;
202
+ pthread_mutex_unlock (& task_list_lock );
203
+
204
+ if (should_notify_platform_thread ) {
205
+ pthread_kill (platform_thread_id , SIGUSR1 );
206
+ }
207
+ }
208
+ bool runs_platform_tasks_on_current_thread (void * userdata ) {
209
+ return pthread_equal (pthread_self (), platform_thread_id ) != 0 ;
210
+ }
211
+
212
+
110
213
/******************
111
214
* INITIALIZATION *
112
215
******************/
113
216
bool setup_paths (void ) {
217
+ #define PATH_EXISTS (path ) (access((path),R_OK)==0)
218
+
114
219
if (!PATH_EXISTS (asset_bundle_path )) {
115
220
fprintf (stderr , "Asset Bundle Directory \"%s\" does not exist\n" , asset_bundle_path );
116
221
return false;
@@ -141,6 +246,8 @@ bool setup_paths(void) {
141
246
}
142
247
143
248
return true;
249
+
250
+ #undef PATH_EXISTS
144
251
}
145
252
146
253
bool init_display (void ) {
@@ -284,6 +391,15 @@ bool init_application(void) {
284
391
project_args .command_line_argc = argc ;
285
392
project_args .command_line_argv = argv ;
286
393
project_args .platform_message_callback = on_platform_message ;
394
+ project_args .custom_task_runners = & (FlutterCustomTaskRunners ) {
395
+ .struct_size = sizeof (FlutterCustomTaskRunners ),
396
+ .platform_task_runner = & (FlutterTaskRunnerDescription ) {
397
+ .struct_size = sizeof (FlutterTaskRunnerDescription ),
398
+ .user_data = NULL ,
399
+ .runs_task_on_current_thread_callback = & runs_platform_tasks_on_current_thread ,
400
+ .post_task_callback = & post_platform_task
401
+ }
402
+ };
287
403
288
404
// spin up the engine
289
405
FlutterEngineResult _result = FlutterEngineRun (FLUTTER_ENGINE_VERSION , & renderer_config , & project_args , NULL , & engine );
@@ -316,7 +432,10 @@ void destroy_application(void) {
316
432
}
317
433
}
318
434
319
- bool init_inputs (void ) {
435
+ /****************
436
+ * Input-Output *
437
+ ****************/
438
+ bool init_io (void ) {
320
439
mouse_filehandle = open ("/dev/input/event0" , O_RDONLY );
321
440
if (mouse_filehandle < 0 ) {
322
441
perror ("error opening the mouse file" );
@@ -325,7 +444,7 @@ bool init_inputs(void) {
325
444
326
445
return true;
327
446
}
328
- bool read_input_events (void ) {
447
+ void * io_loop (void * userdata ) {
329
448
FlutterPointerPhase phase ;
330
449
struct input_event event [64 ];
331
450
bool ok ;
@@ -397,9 +516,25 @@ bool read_input_events(void) {
397
516
printf ("mouse position: %f, %f\n" , mouse_x , mouse_y );
398
517
}
399
518
519
+ return NULL ;
520
+ }
521
+ bool run_io_thread (void ) {
522
+ int ok = pthread_create (& io_thread_id , NULL , & io_loop , NULL );
523
+ if (ok != 0 ) {
524
+ fprintf (stderr , "couldn't create flutter-pi io thread: [%s]" , strerror (ok ));
525
+ return false;
526
+ }
527
+
528
+ ok = pthread_setname_np (io_thread_id , "io.flutter-pi" );
529
+ if (ok != 0 ) {
530
+ fprintf (stderr , "couldn't set name of flutter-pi io thread: [%s]" , strerror (ok ));
531
+ return false;
532
+ }
533
+
400
534
return true;
401
535
}
402
536
537
+
403
538
int main (int argc , const char * const * argv ) {
404
539
if (argc <= 1 ) {
405
540
fprintf (stderr , "Invalid Arguments\n" );
@@ -413,6 +548,10 @@ int main(int argc, const char *const * argv) {
413
548
if (!setup_paths ()) {
414
549
return EXIT_FAILURE ;
415
550
}
551
+
552
+ if (!init_message_loop ()) {
553
+ return EXIT_FAILURE ;
554
+ }
416
555
417
556
// initialize display
418
557
printf ("initializing display...\n" );
@@ -421,7 +560,7 @@ int main(int argc, const char *const * argv) {
421
560
}
422
561
423
562
printf ("Initializing Input devices...\n" );
424
- if (!init_inputs ()) {
563
+ if (!init_io ()) {
425
564
return EXIT_FAILURE ;
426
565
}
427
566
@@ -432,14 +571,16 @@ int main(int argc, const char *const * argv) {
432
571
}
433
572
434
573
// read input events
435
- read_input_events ();
574
+ printf ("Running IO thread...\n" );
575
+ run_io_thread ();
576
+
577
+ // run message loop
578
+ printf ("Running message loop...\n" );
579
+ message_loop ();
436
580
437
581
// exit
438
582
destroy_application ();
439
583
destroy_display ();
440
584
441
585
return EXIT_SUCCESS ;
442
- }
443
-
444
-
445
- #undef PATH_EXISTS
586
+ }
0 commit comments