java_event_thread.c 6.41 KB
Newer Older
Thomas Guillem's avatar
Thomas Guillem committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
/*****************************************************************************
 * java_java_event_thread.c
 *****************************************************************************
 * Copyright © 2015 VLC authors, VideoLAN and VideoLabs
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#include <stdlib.h>
#include <sys/queue.h>
#include <pthread.h>

#include "java_event_thread.h"
#include "utils.h"

#define LOG_TAG "JavaEventThread"
#include "log.h"

#define THREAD_NAME "JavaEventThread"
32
extern JNIEnv *jni_get_env(const char *name);
Thomas Guillem's avatar
Thomas Guillem committed
33 34 35 36 37 38 39 40 41 42 43

typedef struct event_queue_elm event_queue_elm;
struct event_queue_elm
{
    java_event event;
    TAILQ_ENTRY(event_queue_elm) next;
};
typedef TAILQ_HEAD(, event_queue_elm) EVENT_QUEUE;

struct java_event_thread {
    bool b_run;
44
    bool b_sync;
Thomas Guillem's avatar
Thomas Guillem committed
45 46 47 48
    pthread_mutex_t lock;
    pthread_cond_t cond;
    pthread_t thread;
    EVENT_QUEUE queue;
Thomas Guillem's avatar
Thomas Guillem committed
49 50
    jweak jweak;
    jobject jweakCompat;
Thomas Guillem's avatar
Thomas Guillem committed
51 52 53 54 55
};

static void *
JavaEventThread_thread(void *data)
{
56 57
    JNIEnv *env = NULL;
    event_queue_elm *event_elm, *event_elm_next;
Thomas Guillem's avatar
Thomas Guillem committed
58 59
    java_event_thread *p_java_event_thread = data;

60

61
    if (!(env = jni_get_env(THREAD_NAME)))
62 63 64 65
    {
        pthread_mutex_lock(&p_java_event_thread->lock);
        goto end;
    }
Thomas Guillem's avatar
Thomas Guillem committed
66 67

    pthread_mutex_lock(&p_java_event_thread->lock);
68

Thomas Guillem's avatar
Thomas Guillem committed
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
    while (p_java_event_thread->b_run)
    {
        java_event *p_jevent;

        while (p_java_event_thread->b_run &&
               !(event_elm = TAILQ_FIRST(&p_java_event_thread->queue)))
            pthread_cond_wait(&p_java_event_thread->cond,
                              &p_java_event_thread->lock);

        if (!p_java_event_thread->b_run || event_elm == NULL)
            continue;

        p_jevent = &event_elm->event;

        pthread_mutex_unlock(&p_java_event_thread->lock);

Thomas Guillem's avatar
Thomas Guillem committed
85 86 87 88 89 90 91 92 93
        if (p_java_event_thread->jweak)
            (*env)->CallVoidMethod(env, p_java_event_thread->jweak,
                                   fields.VLCObject.dispatchEventFromNativeID,
                                   p_jevent->type, p_jevent->arg1, p_jevent->arg2);
        else
            (*env)->CallStaticVoidMethod(env, fields.VLCObject.clazz,
                                         fields.VLCObject.dispatchEventFromWeakNativeID,
                                         p_java_event_thread->jweakCompat,
                                         p_jevent->type, p_jevent->arg1, p_jevent->arg2);
Thomas Guillem's avatar
Thomas Guillem committed
94 95

        pthread_mutex_lock(&p_java_event_thread->lock);
96 97

        TAILQ_REMOVE(&p_java_event_thread->queue, event_elm, next);
98
        free(event_elm);
99
        pthread_cond_signal(&p_java_event_thread->cond);
Thomas Guillem's avatar
Thomas Guillem committed
100
    }
101 102 103 104 105 106 107 108 109 110
end:
    p_java_event_thread->b_run = false;

    for (event_elm = TAILQ_FIRST(&p_java_event_thread->queue);
         event_elm != NULL; event_elm = event_elm_next)
    {
        event_elm_next = TAILQ_NEXT(event_elm, next);
        TAILQ_REMOVE(&p_java_event_thread->queue, event_elm, next);
        free(event_elm);
    }
Thomas Guillem's avatar
Thomas Guillem committed
111 112 113 114 115 116
    pthread_mutex_unlock(&p_java_event_thread->lock);

    return NULL;
}

java_event_thread *
Thomas Guillem's avatar
Thomas Guillem committed
117
JavaEventThread_create(jweak jweak, jobject jweakCompat, bool b_sync)
Thomas Guillem's avatar
Thomas Guillem committed
118
{
Thomas Guillem's avatar
Thomas Guillem committed
119 120 121 122 123 124
    java_event_thread *p_java_event_thread;

    if (!jweak && !jweakCompat)
        return NULL;

    p_java_event_thread = calloc(1, sizeof(java_event_thread));
Thomas Guillem's avatar
Thomas Guillem committed
125 126 127 128 129 130 131
    if (!p_java_event_thread)
        return NULL;

    pthread_mutex_init(&p_java_event_thread->lock, NULL);
    pthread_cond_init(&p_java_event_thread->cond, NULL);
    TAILQ_INIT(&p_java_event_thread->queue);

132
    pthread_mutex_lock(&p_java_event_thread->lock);
Thomas Guillem's avatar
Thomas Guillem committed
133 134
    p_java_event_thread->jweak = jweak;
    p_java_event_thread->jweakCompat = jweakCompat;
Thomas Guillem's avatar
Thomas Guillem committed
135
    p_java_event_thread->b_run = true;
136
    p_java_event_thread->b_sync = b_sync;
137 138 139 140 141 142 143 144 145
    if (pthread_create(&p_java_event_thread->thread, NULL,
                       JavaEventThread_thread, p_java_event_thread) != 0)
    {
        p_java_event_thread->b_run = false;
        pthread_mutex_unlock(&p_java_event_thread->lock);
        JavaEventThread_destroy(p_java_event_thread);
        p_java_event_thread = NULL;
    } else
        pthread_mutex_unlock(&p_java_event_thread->lock);
Thomas Guillem's avatar
Thomas Guillem committed
146 147 148 149 150 151 152 153

    return p_java_event_thread;
}

void
JavaEventThread_destroy(java_event_thread *p_java_event_thread)
{
    pthread_mutex_lock(&p_java_event_thread->lock);
154 155 156 157 158 159 160 161
    if (p_java_event_thread->b_run)
    {
        p_java_event_thread->b_run = false;
        pthread_cond_signal(&p_java_event_thread->cond);
        pthread_mutex_unlock(&p_java_event_thread->lock);
        pthread_join(p_java_event_thread->thread, NULL);
    } else
        pthread_mutex_unlock(&p_java_event_thread->lock);
Thomas Guillem's avatar
Thomas Guillem committed
162 163 164 165 166 167 168

    pthread_mutex_destroy(&p_java_event_thread->lock);
    pthread_cond_destroy(&p_java_event_thread->cond);

    free(p_java_event_thread);
}

169
int
Thomas Guillem's avatar
Thomas Guillem committed
170 171 172
JavaEventThread_add(java_event_thread *p_java_event_thread,
                    java_event *p_java_event)
{
173 174 175 176 177 178 179 180
    event_queue_elm *event_elm;

    pthread_mutex_lock(&p_java_event_thread->lock);

    if (!p_java_event_thread->b_run)
        goto error;

    event_elm = calloc(1, sizeof(event_queue_elm));
Thomas Guillem's avatar
Thomas Guillem committed
181
    if (!event_elm)
182
        goto error;
Thomas Guillem's avatar
Thomas Guillem committed
183 184
    event_elm->event = *p_java_event;

185 186 187 188
    if (p_java_event_thread->b_sync)
        TAILQ_INSERT_HEAD(&p_java_event_thread->queue, event_elm, next);
    else
        TAILQ_INSERT_TAIL(&p_java_event_thread->queue, event_elm, next);
Thomas Guillem's avatar
Thomas Guillem committed
189
    pthread_cond_signal(&p_java_event_thread->cond);
190 191 192 193 194 195 196 197

    if (p_java_event_thread->b_sync) {
        while (p_java_event_thread->b_run &&
               (event_elm == TAILQ_FIRST(&p_java_event_thread->queue)))
            pthread_cond_wait(&p_java_event_thread->cond,
                              &p_java_event_thread->lock);
    }

Thomas Guillem's avatar
Thomas Guillem committed
198
    pthread_mutex_unlock(&p_java_event_thread->lock);
199 200 201 202
    return 0;
error:
    pthread_mutex_unlock(&p_java_event_thread->lock);
    return -1;
Thomas Guillem's avatar
Thomas Guillem committed
203
}