/**
*Licensed to the Apache Software Foundation (ASF) under one
*or more contributor license agreements. See the NOTICE file
*distributed with this work for additional information
*regarding copyright ownership. The ASF licenses this file
*to you under the Apache License, Version 2.0 (the
*"License"); you may not use this file except in compliance
*with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*Unless required by applicable law or agreed to in writing,
*software distributed under the License is distributed on an
*"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
*specific language governing permissions and limitations
*under the License.
*/
/*
* log.c
*
* \date Jun 26, 2011
* \author Apache Celix Project Team
* \copyright Apache License, Version 2.0
*/
#include
#include
#include
#include
#include "log.h"
#include "linked_list_iterator.h"
#include "array_list.h"
struct log {
LINKED_LIST entries;
apr_thread_mutex_t *lock;
ARRAY_LIST listeners;
ARRAY_LIST listenerEntries;
apr_thread_t *listenerThread;
bool running;
apr_thread_cond_t *entriesToDeliver;
apr_thread_mutex_t *deliverLock;
apr_thread_mutex_t *listenerLock;
apr_pool_t *pool;
};
celix_status_t log_startListenerThread(log_t logger);
celix_status_t log_stopListenerThread(log_t logger);
void * APR_THREAD_FUNC log_listenerThread(apr_thread_t *thread, void *data);
apr_status_t log_destroy(void *logp);
celix_status_t log_create(apr_pool_t *pool, log_t *logger) {
celix_status_t status = CELIX_SUCCESS;
*logger = apr_palloc(pool, sizeof(**logger));
if (*logger == NULL) {
status = CELIX_ENOMEM;
} else {
apr_status_t apr_status;
apr_pool_pre_cleanup_register(pool, *logger, log_destroy);
linkedList_create(pool, &(*logger)->entries);
apr_thread_mutex_create(&(*logger)->lock, APR_THREAD_MUTEX_UNNESTED, pool);
(*logger)->pool = pool;
(*logger)->listeners = NULL;
arrayList_create(pool, &(*logger)->listeners);
(*logger)->listenerEntries = NULL;
arrayList_create(pool, &(*logger)->listenerEntries);
(*logger)->listenerThread = NULL;
(*logger)->running = false;
apr_status = apr_thread_cond_create(&(*logger)->entriesToDeliver, pool);
if (apr_status != APR_SUCCESS) {
status = CELIX_INVALID_SYNTAX;
} else {
apr_status = apr_thread_mutex_create(&(*logger)->deliverLock, 0, pool);
if (apr_status != APR_SUCCESS) {
status = CELIX_INVALID_SYNTAX;
} else {
apr_status = apr_thread_mutex_create(&(*logger)->listenerLock, 0, pool);
if (apr_status != APR_SUCCESS) {
status = CELIX_INVALID_SYNTAX;
} else {
// done
}
}
}
}
return status;
}
apr_status_t log_destroy(void *logp) {
log_t log = logp;
apr_thread_mutex_destroy(log->listenerLock);
apr_thread_mutex_destroy(log->deliverLock);
apr_thread_cond_destroy(log->entriesToDeliver);
arrayList_destroy(log->listenerEntries);
arrayList_destroy(log->listeners);
apr_thread_mutex_destroy(log->lock);
return APR_SUCCESS;
}
celix_status_t log_addEntry(log_t log, log_entry_t entry) {
apr_thread_mutex_lock(log->lock);
linkedList_addElement(log->entries, entry);
// notify any listeners
if (log->listenerThread != NULL)
{
arrayList_add(log->listenerEntries, entry);
apr_thread_cond_signal(log->entriesToDeliver);
}
apr_thread_mutex_unlock(log->lock);
return CELIX_SUCCESS;
}
celix_status_t log_getEntries(log_t log, apr_pool_t *memory_pool, LINKED_LIST *list) {
LINKED_LIST entries = NULL;
if (linkedList_create(memory_pool, &entries) == CELIX_SUCCESS) {
LINKED_LIST_ITERATOR iter = NULL;
apr_thread_mutex_lock(log->lock);
iter = linkedListIterator_create(log->entries, 0);
while (linkedListIterator_hasNext(iter)) {
linkedList_addElement(entries, linkedListIterator_next(iter));
}
*list = entries;
apr_thread_mutex_unlock(log->lock);
return CELIX_SUCCESS;
} else {
return CELIX_ENOMEM;
}
}
celix_status_t log_addLogListener(log_t logger, log_listener_t listener) {
celix_status_t status = CELIX_SUCCESS;
apr_status_t apr_status;
apr_status = apr_thread_mutex_lock(logger->listenerLock);
if (apr_status != APR_SUCCESS) {
status = CELIX_INVALID_SYNTAX;
} else {
arrayList_add(logger->listeners, listener);
if (logger->listenerThread == NULL) {
log_startListenerThread(logger);
}
apr_status = apr_thread_mutex_unlock(logger->listenerLock);
if (apr_status != APR_SUCCESS) {
status = CELIX_INVALID_SYNTAX;
}
}
return status;
}
celix_status_t log_removeLogListener(log_t logger, log_listener_t listener) {
celix_status_t status = CELIX_SUCCESS;
apr_status_t apr_status;
apr_status = apr_thread_mutex_lock(logger->listenerLock);
if (apr_status != APR_SUCCESS) {
status = CELIX_INVALID_SYNTAX;
} else {
arrayList_removeElement(logger->listeners, listener);
if (arrayList_size(logger->listeners) == 0) {
log_stopListenerThread(logger);
}
apr_status = apr_thread_mutex_unlock(logger->listenerLock);
if (apr_status != APR_SUCCESS) {
status = CELIX_INVALID_SYNTAX;
}
}
return status;
}
celix_status_t log_removeAllLogListener(log_t logger) {
celix_status_t status = CELIX_SUCCESS;
apr_status_t apr_status;
apr_status = apr_thread_mutex_lock(logger->listenerLock);
if (apr_status != APR_SUCCESS) {
status = CELIX_INVALID_SYNTAX;
} else {
arrayList_clear(logger->listeners);
apr_status = apr_thread_mutex_unlock(logger->listenerLock);
if (apr_status != APR_SUCCESS) {
status = CELIX_INVALID_SYNTAX;
}
}
return status;
}
celix_status_t log_startListenerThread(log_t logger) {
celix_status_t status = CELIX_SUCCESS;
apr_status_t apr_status;
logger->running = true;
apr_status = apr_thread_create(&logger->listenerThread, NULL, log_listenerThread, logger, logger->pool);
if (apr_status != APR_SUCCESS) {
status = CELIX_INVALID_SYNTAX;
}
return status;
}
celix_status_t log_stopListenerThread(log_t logger) {
celix_status_t status = CELIX_SUCCESS;
apr_status_t apr_status = APR_SUCCESS;
apr_status = apr_thread_mutex_lock(logger->deliverLock);
if (apr_status != APR_SUCCESS) {
status = CELIX_INVALID_SYNTAX;
} else {
apr_status_t stat;
logger->running = false;
apr_thread_cond_signal(logger->entriesToDeliver);
status = apr_thread_mutex_unlock(logger->deliverLock);
if (status != APR_SUCCESS) {
status = CELIX_INVALID_SYNTAX;
} else {
//apr_thread_join(&stat, logger->listenerThread);
logger->listenerThread = NULL;
}
}
return status;
}
void * APR_THREAD_FUNC log_listenerThread(apr_thread_t *thread, void *data) {
apr_status_t status = APR_SUCCESS;
log_t logger = data;
while (logger->running) {
status = apr_thread_mutex_lock(logger->deliverLock);
if (status != APR_SUCCESS) {
logger->running = false;
} else {
if (!arrayList_isEmpty(logger->listenerEntries)) {
log_entry_t entry = (log_entry_t) arrayList_remove(logger->listenerEntries, 0);
status = apr_thread_mutex_lock(logger->listenerLock);
if (status != APR_SUCCESS) {
logger->running = false;
break;
} else {
ARRAY_LIST_ITERATOR it = arrayListIterator_create(logger->listeners);
while (arrayListIterator_hasNext(it)) {
log_listener_t listener = arrayListIterator_next(it);
listener->logged(listener, entry);
}
status = apr_thread_mutex_unlock(logger->listenerLock);
if (status != APR_SUCCESS) {
logger->running = false;
break;
}
}
}
if (arrayList_isEmpty(logger->listenerEntries)) {
apr_thread_cond_wait(logger->entriesToDeliver, logger->deliverLock);
}
status = apr_thread_mutex_unlock(logger->deliverLock);
if (status != APR_SUCCESS) {
logger->running = false;
break;
}
}
}
apr_thread_exit(thread, status);
return NULL;
}