Annotation of qemu/buffered_file.c, revision 1.1.1.1

1.1       root        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: 
                    232:     s->opaque = opaque;
                    233:     s->xfer_limit = bytes_per_sec / 10;
                    234:     s->put_buffer = put_buffer;
                    235:     s->put_ready = put_ready;
                    236:     s->wait_for_unfreeze = wait_for_unfreeze;
                    237:     s->close = close;
                    238: 
                    239:     s->file = qemu_fopen_ops(s, buffered_put_buffer, NULL,
                    240:                              buffered_close, buffered_rate_limit);
                    241: 
                    242:     s->timer = qemu_new_timer(rt_clock, buffered_rate_tick, s);
                    243: 
                    244:     qemu_mod_timer(s->timer, qemu_get_clock(rt_clock) + 100);
                    245: 
                    246:     return s->file;
                    247: }

unix.superglobalmegacorp.com