D.1 Local Atomic Logging

Team-FLY

The local atomic logging library is described in Section 4.9.1. This library allows messages to be atomically written to a file descriptor. A message may be made up of pieces, which are assembled by the logging library and sent atomically. There are no a priori limits to the sizes of the pieces, the number of pieces, or the total size of the message. However, the logger reports an error if the total amount to be logged with a single call to atomic_log_send cannot be written with a single call to write . Multiple processes may concurrently log data to the same file or different files. The library uses static data and should not be used by concurrent threads.

Programs that use this library include the atomic_logger.h file shown in Program D.1 and are linked with atomic_logger.c shown in Program D.2. All the public functions in the library return 0 if successful or “1 on error. A program uses the logging facility as follows .

  1. Call atomic_log_open with the name of the log file as the parameter.

  2. Call any of the functions atomic_log_array , atomic_log_printf and atomic_log_string to create pieces of the message.

  3. Call atomic_log_send to log the message. This logging deletes the pieces of the message that have been saved in the logger.

  4. Repeat steps 2 and 3 as often as you like.

  5. The program can use the atomic_log_clear function to discard the pieces of the message generated so far without sending them.

  6. Call atomic_log_close when logging to this file is complete.

Each piece that is logged is put in a linked list. The function atomic_log_send allocates a contiguous block large enough to hold all the pieces, copies the pieces into this block, and sends them to the log file with a single call to write . The atomic_log_send function returns 0 only if write actually writes all the requested bytes.

When strings are logged with atomic_log_printf or atomic_log_string , the facility saves the string terminator with each piece. These functions call the insert_new_entry function with extra equal to 1. The logger allocates space for the string terminator but does not count the terminator in the length field and does not send the terminator to the log file.

Program D.1 atomic_logger.h

The header file for the atomic logging module .

 int atomic_log_array(char *s, int len); int atomic_log_clear(); int atomic_log_close(); int atomic_log_open(char *fn); int atomic_log_printf(char *fmt, ...); int atomic_log_send(); int atomic_log_string(char *s); 
Program D.2 atomic_logger.c

An implementation of the atomic logging module .

 #include <errno.h> #include <fcntl.h> #include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/stat.h> #define FILE_PERMS (S_IRUSR  S_IWUSR S_IRGRP  S_IROTH) #define OPEN_FLAGS (O_WRONLYO_APPENDO_CREAT) typedef struct list {    char *entry;    int len;    struct list *next; } list; static int fd = -1; static list *first = NULL; static list *last = NULL; /* -----------------------------------------------------------------    Private Functions */ /* This is the same as write, but restarts if interrupted by a signal */ static ssize_t my_write(int fd, void *buf, size_t size) {    ssize_t bytes;    while (((bytes = write(fd, buf, size)) == -1) && (errno == EINTR));    return bytes; } /* Insert an entry with the given len field, but allocate extra bytes.*/ /* Return a pointer to the new entry on success or NULL on failure.   */ static list *insert_new_entry(int len, int extra) {    char *new_str;    list *new_entry;    new_entry = (list *)malloc(sizeof(list)+len+extra);    if (new_entry == NULL)       return NULL;    new_str = (char *)new_entry+sizeof(list);    new_entry->entry = new_str;    new_entry->next = NULL;    new_entry->len = len;    if (last == NULL)       first = new_entry;    else       last->next = new_entry;    last = new_entry;    return new_entry; } /* Return the sum of the lengths of all the entries.                  */ static int get_length() {    int len = 0;    list *current;    current = first;    while (current != NULL) {       len += current->len;       current = current->next;    }    return len; } /* Clear the list and free all the space.                             */ static void clear() {    list *current;    list *free_entry;    current = first;    while (current != NULL) {       free_entry = current;       current = current->next;       free(free_entry);    }    first = NULL;    last = NULL; } /* -----------------------------------------------------------------    Public Functions */ /* Open the given file for logging.                                   */ /* If successful, return 0.  Otherwise, return -1 with errno set.     */ int atomic_log_open(char *fn) {    while (fd = open(fn, OPEN_FLAGS, FILE_PERMS), fd == -1 && errno == EINTR);    if (fd < 0)       return -1;    return 0; } /* Insert the given array with given size in the list.                */ /* If successful, return 0.  Otherwise, return -1 with errno set.     */ int atomic_log_array(char *s, int len) {    list *new_entry;    if (fd < 0) {       errno = EINVAL;       return -1;    }    new_entry = insert_new_entry(len, 0);    if (new_entry == NULL)       return -1;    (void)memcpy(new_entry->entry, s, len);    return 0; } /* Insert the given string in the list.                               */ /* Do not include the string terminator.                              */ /* If successful, return 0.  Otherwise, return -1 with errno set.     */ int atomic_log_string(char *s) {    return atomic_log_array(s, strlen(s)); } /* Insert an entry in the list.                                       */ /* The syntax is similar to printf.                                   */ /* Include the string terminator but do not count it in the length.   */ /* If successful, return 0.  Otherwise, return -1 with errno set.     */ int atomic_log_printf(char *fmt, ...) {    va_list ap;    char ch;    int len;    list *new_entry;    if (fd < 0) {       errno = EINVAL;       return -1;    }    va_start(ap, fmt);    len = vsnprintf(&ch, 1, fmt, ap);    new_entry = insert_new_entry(len, 1);    if (new_entry == NULL)       return -1;    vsprintf(new_entry->entry, fmt, ap);    return 0; } /* Attempt to log the entire list with a single write.                */ /* Clear the list if successful.                                      */ /* If successful, return 0.  Otherwise, return -1 with errno set.     */ /* If the entire list cannot be logged with a single write, this is   */ /*   considered a failure.                                            */ int atomic_log_send() {    char *buf;    list *current;    int len;    if (fd < 0) {       errno = EINVAL;       return -1;    }    len = get_length();    if (len == 0)       return 0;    buf = (char *)malloc(len);    if (buf == NULL)       return -1;    current = first;    len = 0;    while (current != NULL) {       (void)memcpy(buf+len, current->entry, current->len);       len += current->len;       current = current->next;    }    if (my_write(fd, buf, len) != len) {       free(buf);       errno = EAGAIN;       return -1;    }    free(buf);    clear();    return 0; } /* Clear the list and free all the space without logging anything.    */ int atomic_log_clear() {    clear();    return 0; } /* Close the log file.  Any data not yet logged is lost.              */ int atomic_log_close() {    int retval;    clear();    while (retval = close(fd), retval == -1 && errno == EINTR) ;    return retval; } 
Team-FLY


Unix Systems Programming
UNIX Systems Programming: Communication, Concurrency and Threads
ISBN: 0130424110
EAN: 2147483647
Year: 2003
Pages: 274

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net