Home | History | Annotate | Download | only in jni
      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