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 50 void* looper::trampoline(void* p) { 51 ((looper*)p)->loop(); 52 return NULL; 53 } 54 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 66 looper::~looper() { 67 if (running) { 68 LOGV("Looper deleted while still running. Some messages will not be processed"); 69 quit(); 70 } 71 } 72 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 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 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 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 149 void looper::handle(int what, void* obj) { 150 LOGV("dropping msg %d %p", what, obj); 151 } 152 153