1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "looper.h"
18 
19 #include <assert.h>
20 #include <jni.h>
21 #include <pthread.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <fcntl.h>
28 #include <errno.h>
29 #include <limits.h>
30 #include <semaphore.h>
31 
32 // for __android_log_print(ANDROID_LOG_INFO, "YourApp", "formatted message");
33 #include <android/log.h>
34 #define TAG "NativeCodec-looper"
35 #define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, TAG, __VA_ARGS__)
36 
37 
38 struct loopermessage;
39 typedef struct loopermessage loopermessage;
40 
41 struct loopermessage {
42     int what;
43     void *obj;
44     loopermessage *next;
45     bool quit;
46 };
47 
48 
49 
trampoline(void * p)50 void* looper::trampoline(void* p) {
51     ((looper*)p)->loop();
52     return NULL;
53 }
54 
looper()55 looper::looper() {
56     sem_init(&headdataavailable, 0, 0);
57     sem_init(&headwriteprotect, 0, 1);
58     pthread_attr_t attr;
59     pthread_attr_init(&attr);
60 
61     pthread_create(&worker, &attr, trampoline, this);
62     running = true;
63 }
64 
65 
~looper()66 looper::~looper() {
67     if (running) {
68         LOGV("Looper deleted while still running. Some messages will not be processed");
69         quit();
70     }
71 }
72 
post(int what,void * data,bool flush)73 void looper::post(int what, void *data, bool flush) {
74     loopermessage *msg = new loopermessage();
75     msg->what = what;
76     msg->obj = data;
77     msg->next = NULL;
78     msg->quit = false;
79     addmsg(msg, flush);
80 }
81 
addmsg(loopermessage * msg,bool flush)82 void looper::addmsg(loopermessage *msg, bool flush) {
83     sem_wait(&headwriteprotect);
84     loopermessage *h = head;
85 
86     if (flush) {
87         while(h) {
88             loopermessage *next = h->next;
89             delete h;
90             h = next;
91         }
92         h = NULL;
93     }
94     if (h) {
95         while (h->next) {
96             h = h->next;
97         }
98         h->next = msg;
99     } else {
100         head = msg;
101     }
102     LOGV("post msg %d", msg->what);
103     sem_post(&headwriteprotect);
104     sem_post(&headdataavailable);
105 }
106 
loop()107 void looper::loop() {
108     while(true) {
109         // wait for available message
110         sem_wait(&headdataavailable);
111 
112         // get next available message
113         sem_wait(&headwriteprotect);
114         loopermessage *msg = head;
115         if (msg == NULL) {
116             LOGV("no msg");
117             sem_post(&headwriteprotect);
118             continue;
119         }
120         head = msg->next;
121         sem_post(&headwriteprotect);
122 
123         if (msg->quit) {
124             LOGV("quitting");
125             delete msg;
126             return;
127         }
128         LOGV("processing msg %d", msg->what);
129         handle(msg->what, msg->obj);
130         delete msg;
131     }
132 }
133 
quit()134 void looper::quit() {
135     LOGV("quit");
136     loopermessage *msg = new loopermessage();
137     msg->what = 0;
138     msg->obj = NULL;
139     msg->next = NULL;
140     msg->quit = true;
141     addmsg(msg, false);
142     void *retval;
143     pthread_join(worker, &retval);
144     sem_destroy(&headdataavailable);
145     sem_destroy(&headwriteprotect);
146     running = false;
147 }
148 
handle(int what,void * obj)149 void looper::handle(int what, void* obj) {
150     LOGV("dropping msg %d %p", what, obj);
151 }
152 
153