summaryrefslogblamecommitdiffstats
path: root/hw4/chttpd/chttpd-log.c
blob: 7214a29914f19c30b4cf83d9e460c702ee06efa8 (plain) (tree)
1
2
3
4
5
6
7
8
9





                         
                    
                   
                    
 


                    
                   
                   

                                                          

                                                          














                                                                


                                                    













                                                                                  
                                              
                          

                                                   



                                         
                                              

                                   





                                                                                      
                            


                                                           



                                             
                                                          


                                             
                                                
























                                                                            
                                                                


                                                       
                                                
                                                       

                                                       

                 
 
/* b01902062 藍挺瑋 */
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include "chttpd-log.h"
#include "memwrap.h"
#include <l4list.h>
#include <l4posix.h>

#include <fcntl.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

ChttpdLog* chttpd_log_new (const char* name, int log_fd) {
    char* name_start = strrchr (name, '/');
    name = name_start == NULL ? name : name_start + 1;
    size_t name_len = (name == NULL) ? 0 : strlen (name);
    char* mem = xmalloc (sizeof (ChttpdLog) + name_len + 1);
    void* mem_generic = mem;

    ChttpdLog* hlog = mem_generic;
    hlog->name = mem + sizeof (ChttpdLog);
    if (name != NULL) {
        strncpy (hlog->name, name, name_len + 1);
    }
    hlog->name[name_len] = '\0';

    hlog->ref_count = 1;
    hlog->pid = getpid ();
    hlog->log_fd = log_fd;
    hlog->log_data = lbs_list_meta_new (free);
    pthread_cond_init (&hlog->ref_change, NULL);
    pthread_mutex_init (&hlog->ref_mutex, NULL);
    pthread_rwlock_init (&hlog->log_lock, NULL);

    return hlog;
}

ChttpdLog* chttpd_log_new_file (const char* name, const char* file) {
    int log_fd = open (file, O_WRONLY | O_APPEND | O_CREAT | O_CLOEXEC, 0600);
    if (log_fd < 0) {
        return NULL;
    }

    return chttpd_log_new (name, log_fd);
}

ChttpdLog* chttpd_log_ref (ChttpdLog* hlog) {
    pthread_mutex_lock (&hlog->ref_mutex);
    hlog->ref_count++;
    pthread_mutex_unlock (&hlog->ref_mutex);
    pthread_cond_broadcast (&hlog->ref_change);
    return hlog;
}

void chttpd_log_unref (ChttpdLog* hlog) {
    pthread_mutex_lock (&hlog->ref_mutex);
    hlog->ref_count--;
    if (hlog->ref_count <= 0) {
        /* No thread has a reference on hlog, so we are going to destory it */
        pthread_mutex_unlock (&hlog->ref_mutex);
        pthread_mutex_destroy (&hlog->ref_mutex);
        pthread_cond_destroy (&hlog->ref_change);
        pthread_rwlock_destroy (&hlog->log_lock);
        lbs_list_meta_free (hlog->log_data);
        free (hlog);
    } else {
        pthread_mutex_unlock (&hlog->ref_mutex);
        pthread_cond_broadcast (&hlog->ref_change);
    }
}

int chttpd_log_read_start (ChttpdLog* hlog) {
    return pthread_rwlock_tryrdlock (&hlog->log_lock);
}

void chttpd_log_read_stop (ChttpdLog* hlog) {
    pthread_rwlock_unlock (&hlog->log_lock);
}

size_t chttpd_log_write (ChttpdLog* hlog, const char* format, ...) {
    va_list ap;
    char* str;
    size_t r;

    va_start (ap, format);
    str = lbs_str_vprintf (format, ap);
    va_end (ap);

    r = chttpd_log_write_str (hlog, str);
    free (str);
    return r;
}

size_t chttpd_log_write_str (ChttpdLog* hlog, const char* string) {
    time_t t;
    struct tm tmd;
    char* msg;
    size_t r;

    time (&t);
    localtime_r (&t, &tmd);
    msg = lbs_str_printf ("%04d-%02d-%02d %02d:%02d:%02d %s[%ld]: %s\n",
        tmd.tm_year + 1900, tmd.tm_mon + 1, tmd.tm_mday,
        tmd.tm_hour, tmd.tm_min, tmd.tm_sec,
        hlog->name, (long)(hlog->pid), string);

    pthread_rwlock_wrlock (&hlog->log_lock);
    lbs_list_push_back (hlog->log_data, msg, NULL);
    r = lbs_posix_write_all (hlog->log_fd, msg, 0);
    pthread_rwlock_unlock (&hlog->log_lock);

    return r;
}