symbian-qemu-0.9.1-12/qemu-symbian-svp/buffered_file.c
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     1 /*
       
     2  * QEMU buffered QEMUFile
       
     3  *
       
     4  * Copyright IBM, Corp. 2008
       
     5  *
       
     6  * Authors:
       
     7  *  Anthony Liguori   <aliguori@us.ibm.com>
       
     8  *
       
     9  * This work is licensed under the terms of the GNU GPL, version 2.  See
       
    10  * the COPYING file in the top-level directory.
       
    11  *
       
    12  */
       
    13 
       
    14 #include "qemu-common.h"
       
    15 #include "hw/hw.h"
       
    16 #include "qemu-timer.h"
       
    17 #include "sysemu.h"
       
    18 #include "qemu-char.h"
       
    19 #include "buffered_file.h"
       
    20 
       
    21 //#define DEBUG_BUFFERED_FILE
       
    22 
       
    23 typedef struct QEMUFileBuffered
       
    24 {
       
    25     BufferedPutFunc *put_buffer;
       
    26     BufferedPutReadyFunc *put_ready;
       
    27     BufferedWaitForUnfreezeFunc *wait_for_unfreeze;
       
    28     BufferedCloseFunc *close;
       
    29     void *opaque;
       
    30     QEMUFile *file;
       
    31     int has_error;
       
    32     int freeze_output;
       
    33     size_t bytes_xfer;
       
    34     size_t xfer_limit;
       
    35     uint8_t *buffer;
       
    36     size_t buffer_size;
       
    37     size_t buffer_capacity;
       
    38     QEMUTimer *timer;
       
    39 } QEMUFileBuffered;
       
    40 
       
    41 #ifdef DEBUG_BUFFERED_FILE
       
    42 #define dprintf(fmt, ...) \
       
    43     do { printf("buffered-file: " fmt, ## __VA_ARGS__); } while (0)
       
    44 #else
       
    45 #define dprintf(fmt, ...) \
       
    46     do { } while (0)
       
    47 #endif
       
    48 
       
    49 static void buffered_append(QEMUFileBuffered *s,
       
    50                             const uint8_t *buf, size_t size)
       
    51 {
       
    52     if (size > (s->buffer_capacity - s->buffer_size)) {
       
    53         void *tmp;
       
    54 
       
    55         dprintf("increasing buffer capacity from %ld by %ld\n",
       
    56                 s->buffer_capacity, size + 1024);
       
    57 
       
    58         s->buffer_capacity += size + 1024;
       
    59 
       
    60         tmp = qemu_realloc(s->buffer, s->buffer_capacity);
       
    61         if (tmp == NULL) {
       
    62             fprintf(stderr, "qemu file buffer expansion failed\n");
       
    63             exit(1);
       
    64         }
       
    65 
       
    66         s->buffer = tmp;
       
    67     }
       
    68 
       
    69     memcpy(s->buffer + s->buffer_size, buf, size);
       
    70     s->buffer_size += size;
       
    71 }
       
    72 
       
    73 static void buffered_flush(QEMUFileBuffered *s)
       
    74 {
       
    75     size_t offset = 0;
       
    76 
       
    77     if (s->has_error) {
       
    78         dprintf("flush when error, bailing\n");
       
    79         return;
       
    80     }
       
    81 
       
    82     dprintf("flushing %ld byte(s) of data\n", s->buffer_size);
       
    83 
       
    84     while (offset < s->buffer_size) {
       
    85         ssize_t ret;
       
    86 
       
    87         ret = s->put_buffer(s->opaque, s->buffer + offset,
       
    88                             s->buffer_size - offset);
       
    89         if (ret == -EAGAIN) {
       
    90             dprintf("backend not ready, freezing\n");
       
    91             s->freeze_output = 1;
       
    92             break;
       
    93         }
       
    94 
       
    95         if (ret <= 0) {
       
    96             dprintf("error flushing data, %ld\n", ret);
       
    97             s->has_error = 1;
       
    98             break;
       
    99         } else {
       
   100             dprintf("flushed %ld byte(s)\n", ret);
       
   101             offset += ret;
       
   102         }
       
   103     }
       
   104 
       
   105     dprintf("flushed %ld of %ld byte(s)\n", offset, s->buffer_size);
       
   106     memmove(s->buffer, s->buffer + offset, s->buffer_size - offset);
       
   107     s->buffer_size -= offset;
       
   108 }
       
   109 
       
   110 static int buffered_put_buffer(void *opaque, const uint8_t *buf, int64_t pos, int size)
       
   111 {
       
   112     QEMUFileBuffered *s = opaque;
       
   113     int offset = 0;
       
   114     ssize_t ret;
       
   115 
       
   116     dprintf("putting %ld bytes at %Ld\n", size, pos);
       
   117 
       
   118     if (s->has_error) {
       
   119         dprintf("flush when error, bailing\n");
       
   120         return -EINVAL;
       
   121     }
       
   122 
       
   123     dprintf("unfreezing output\n");
       
   124     s->freeze_output = 0;
       
   125 
       
   126     buffered_flush(s);
       
   127 
       
   128     while (!s->freeze_output && offset < size) {
       
   129         if (s->bytes_xfer > s->xfer_limit) {
       
   130             dprintf("transfer limit exceeded when putting\n");
       
   131             break;
       
   132         }
       
   133 
       
   134         ret = s->put_buffer(s->opaque, buf + offset, size - offset);
       
   135         if (ret == -EAGAIN) {
       
   136             dprintf("backend not ready, freezing\n");
       
   137             s->freeze_output = 1;
       
   138             break;
       
   139         }
       
   140 
       
   141         if (ret <= 0) {
       
   142             dprintf("error putting\n");
       
   143             s->has_error = 1;
       
   144             offset = -EINVAL;
       
   145             break;
       
   146         }
       
   147 
       
   148         dprintf("put %ld byte(s)\n", ret);
       
   149         offset += ret;
       
   150         s->bytes_xfer += ret;
       
   151     }
       
   152 
       
   153     if (offset >= 0) {
       
   154         dprintf("buffering %ld bytes\n", size - offset);
       
   155         buffered_append(s, buf + offset, size - offset);
       
   156         offset = size;
       
   157     }
       
   158 
       
   159     return offset;
       
   160 }
       
   161 
       
   162 static int buffered_close(void *opaque)
       
   163 {
       
   164     QEMUFileBuffered *s = opaque;
       
   165     int ret;
       
   166 
       
   167     dprintf("closing\n");
       
   168 
       
   169     while (!s->has_error && s->buffer_size) {
       
   170         buffered_flush(s);
       
   171         if (s->freeze_output)
       
   172             s->wait_for_unfreeze(s);
       
   173     }
       
   174 
       
   175     ret = s->close(s->opaque);
       
   176 
       
   177     qemu_del_timer(s->timer);
       
   178     qemu_free_timer(s->timer);
       
   179     qemu_free(s->buffer);
       
   180     qemu_free(s);
       
   181 
       
   182     return ret;
       
   183 }
       
   184 
       
   185 static int buffered_rate_limit(void *opaque)
       
   186 {
       
   187     QEMUFileBuffered *s = opaque;
       
   188 
       
   189     if (s->has_error)
       
   190         return 0;
       
   191 
       
   192     if (s->freeze_output)
       
   193         return 1;
       
   194 
       
   195     if (s->bytes_xfer > s->xfer_limit)
       
   196         return 1;
       
   197 
       
   198     return 0;
       
   199 }
       
   200 
       
   201 static void buffered_rate_tick(void *opaque)
       
   202 {
       
   203     QEMUFileBuffered *s = opaque;
       
   204 
       
   205     if (s->has_error)
       
   206         return;
       
   207 
       
   208     qemu_mod_timer(s->timer, qemu_get_clock(rt_clock) + 100);
       
   209 
       
   210     if (s->freeze_output)
       
   211         return;
       
   212 
       
   213     s->bytes_xfer = 0;
       
   214 
       
   215     buffered_flush(s);
       
   216 
       
   217     /* Add some checks around this */
       
   218     s->put_ready(s->opaque);
       
   219 }
       
   220 
       
   221 QEMUFile *qemu_fopen_ops_buffered(void *opaque,
       
   222                                   size_t bytes_per_sec,
       
   223                                   BufferedPutFunc *put_buffer,
       
   224                                   BufferedPutReadyFunc *put_ready,
       
   225                                   BufferedWaitForUnfreezeFunc *wait_for_unfreeze,
       
   226                                   BufferedCloseFunc *close)
       
   227 {
       
   228     QEMUFileBuffered *s;
       
   229 
       
   230     s = qemu_mallocz(sizeof(*s));
       
   231     if (s == NULL)
       
   232         return NULL;
       
   233 
       
   234     s->opaque = opaque;
       
   235     s->xfer_limit = bytes_per_sec / 10;
       
   236     s->put_buffer = put_buffer;
       
   237     s->put_ready = put_ready;
       
   238     s->wait_for_unfreeze = wait_for_unfreeze;
       
   239     s->close = close;
       
   240 
       
   241     s->file = qemu_fopen_ops(s, buffered_put_buffer, NULL,
       
   242                              buffered_close, buffered_rate_limit);
       
   243 
       
   244     s->timer = qemu_new_timer(rt_clock, buffered_rate_tick, s);
       
   245 
       
   246     qemu_mod_timer(s->timer, qemu_get_clock(rt_clock) + 100);
       
   247 
       
   248     return s->file;
       
   249 }