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