mirror of
https://gitlab.uni-freiburg.de/opensourcevdi/spice
synced 2025-12-30 17:49:02 +00:00
replay: better record encapsulation
Remove global/static from red_record_qxl.c. Defined a structure and use it to hold record state. Signed-off-by: Frediano Ziglio <fziglio@redhat.com> Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
This commit is contained in:
parent
1d3cd7d617
commit
751a0aeb51
@ -26,6 +26,12 @@
|
||||
#include "memslot.h"
|
||||
#include "red-parse-qxl.h"
|
||||
#include "zlib-encoder.h"
|
||||
#include "red-record-qxl.h"
|
||||
|
||||
struct RedRecord {
|
||||
FILE *fd;
|
||||
unsigned int counter;
|
||||
};
|
||||
|
||||
#if 0
|
||||
static void hexdump_qxl(RedMemSlotInfo *slots, int group_id,
|
||||
@ -782,9 +788,11 @@ void red_record_cursor_cmd(FILE *fd, RedMemSlotInfo *slots, int group_id,
|
||||
}
|
||||
}
|
||||
|
||||
void red_record_dev_input_primary_surface_create(FILE *fd,
|
||||
void red_record_dev_input_primary_surface_create(RedRecord *record,
|
||||
QXLDevSurfaceCreate* surface, uint8_t *line_0)
|
||||
{
|
||||
FILE *fd = record->fd;
|
||||
|
||||
fprintf(fd, "%d %d %d %d\n", surface->width, surface->height,
|
||||
surface->stride, surface->format);
|
||||
fprintf(fd, "%d %d %d %d\n", surface->position, surface->mouse_mode,
|
||||
@ -793,22 +801,22 @@ void red_record_dev_input_primary_surface_create(FILE *fd,
|
||||
line_0);
|
||||
}
|
||||
|
||||
void red_record_event(FILE *fd, int what, uint32_t type, unsigned long ts)
|
||||
void red_record_event(RedRecord *record, int what, uint32_t type, unsigned long ts)
|
||||
{
|
||||
static int counter = 0;
|
||||
|
||||
// TODO: record the size of the packet in the header. This would make
|
||||
// navigating it much faster (well, I can add an index while I'm at it..)
|
||||
// and make it trivial to get a histogram from a file.
|
||||
// But to implement that I would need some temporary buffer for each event.
|
||||
// (that can be up to VGA_FRAMEBUFFER large)
|
||||
fprintf(fd, "event %d %d %u %lu\n", counter++, what, type, ts);
|
||||
fprintf(record->fd, "event %u %d %u %lu\n", record->counter++, what, type, ts);
|
||||
}
|
||||
|
||||
void red_record_qxl_command(FILE *fd, RedMemSlotInfo *slots,
|
||||
void red_record_qxl_command(RedRecord *record, RedMemSlotInfo *slots,
|
||||
QXLCommandExt ext_cmd, unsigned long ts)
|
||||
{
|
||||
red_record_event(fd, 0, ext_cmd.cmd.type, ts);
|
||||
FILE *fd = record->fd;
|
||||
|
||||
red_record_event(record, 0, ext_cmd.cmd.type, ts);
|
||||
|
||||
switch (ext_cmd.cmd.type) {
|
||||
case QXL_CMD_DRAW:
|
||||
@ -825,3 +833,33 @@ void red_record_qxl_command(FILE *fd, RedMemSlotInfo *slots,
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
RedRecord *red_record_new(const char *filename)
|
||||
{
|
||||
static const char header[] = "SPICE_REPLAY 1\n";
|
||||
|
||||
FILE *f;
|
||||
RedRecord *record;
|
||||
|
||||
f = fopen(filename, "w+");
|
||||
if (!f) {
|
||||
spice_error("failed to open recording file %s\n", filename);
|
||||
}
|
||||
|
||||
if (fwrite(header, sizeof(header)-1, 1, f) != 1) {
|
||||
spice_error("failed to write replay header");
|
||||
}
|
||||
|
||||
record = g_new(RedRecord, 1);
|
||||
record->fd = f;
|
||||
record->counter = 0;
|
||||
return record;
|
||||
}
|
||||
|
||||
void red_record_free(RedRecord *record)
|
||||
{
|
||||
if (record) {
|
||||
fclose(record->fd);
|
||||
g_free(record);
|
||||
}
|
||||
}
|
||||
|
||||
@ -24,12 +24,23 @@
|
||||
#include "red-common.h"
|
||||
#include "memslot.h"
|
||||
|
||||
void red_record_dev_input_primary_surface_create(
|
||||
FILE *fd, QXLDevSurfaceCreate *surface, uint8_t *line_0);
|
||||
typedef struct RedRecord RedRecord;
|
||||
|
||||
void red_record_event(FILE *fd, int what, uint32_t type, unsigned long ts);
|
||||
/**
|
||||
* Create a new structure to handle recording.
|
||||
* This function never returns NULL.
|
||||
*/
|
||||
RedRecord* red_record_new(const char *filename);
|
||||
|
||||
void red_record_qxl_command(FILE *fd, RedMemSlotInfo *slots,
|
||||
void red_record_free(RedRecord *record);
|
||||
|
||||
void red_record_dev_input_primary_surface_create(RedRecord *record,
|
||||
QXLDevSurfaceCreate *surface,
|
||||
uint8_t *line_0);
|
||||
|
||||
void red_record_event(RedRecord *record, int what, uint32_t type, unsigned long ts);
|
||||
|
||||
void red_record_qxl_command(RedRecord *record, RedMemSlotInfo *slots,
|
||||
QXLCommandExt ext_cmd, unsigned long ts);
|
||||
|
||||
#endif
|
||||
|
||||
@ -88,7 +88,7 @@ struct RedWorker {
|
||||
|
||||
int driver_cap_monitors_config;
|
||||
|
||||
FILE *record_fd;
|
||||
RedRecord *record;
|
||||
};
|
||||
|
||||
static RedsState* red_worker_get_server(RedWorker *worker);
|
||||
@ -215,8 +215,8 @@ static int red_process_display(RedWorker *worker, int *ring_is_empty)
|
||||
return n;
|
||||
}
|
||||
|
||||
if (worker->record_fd)
|
||||
red_record_qxl_command(worker->record_fd, &worker->mem_slots, ext_cmd,
|
||||
if (worker->record)
|
||||
red_record_qxl_command(worker->record, &worker->mem_slots, ext_cmd,
|
||||
stat_now(CLOCK_MONOTONIC));
|
||||
|
||||
stat_inc_counter(reds, worker->command_counter, 1);
|
||||
@ -663,9 +663,9 @@ static void dev_create_primary_surface(RedWorker *worker, uint32_t surface_id,
|
||||
if (error) {
|
||||
return;
|
||||
}
|
||||
if (worker->record_fd) {
|
||||
red_record_dev_input_primary_surface_create(worker->record_fd,
|
||||
&surface, line_0);
|
||||
if (worker->record) {
|
||||
red_record_dev_input_primary_surface_create(worker->record,
|
||||
&surface, line_0);
|
||||
}
|
||||
|
||||
if (surface.stride < 0) {
|
||||
@ -1176,7 +1176,7 @@ static void worker_dispatcher_record(void *opaque, uint32_t message_type, void *
|
||||
{
|
||||
RedWorker *worker = opaque;
|
||||
|
||||
red_record_event(worker->record_fd, 1, message_type, stat_now(CLOCK_MONOTONIC));
|
||||
red_record_event(worker->record, 1, message_type, stat_now(CLOCK_MONOTONIC));
|
||||
}
|
||||
|
||||
static void register_callbacks(Dispatcher *dispatcher)
|
||||
@ -1456,22 +1456,14 @@ RedWorker* red_worker_new(QXLInstance *qxl,
|
||||
|
||||
record_filename = getenv("SPICE_WORKER_RECORD_FILENAME");
|
||||
if (record_filename) {
|
||||
static const char header[] = "SPICE_REPLAY 1\n";
|
||||
|
||||
worker->record_fd = fopen(record_filename, "w+");
|
||||
if (worker->record_fd == NULL) {
|
||||
spice_error("failed to open recording file %s\n", record_filename);
|
||||
}
|
||||
if (fwrite(header, sizeof(header)-1, 1, worker->record_fd) != 1) {
|
||||
spice_error("failed to write replay header");
|
||||
}
|
||||
worker->record = red_record_new(record_filename);
|
||||
}
|
||||
dispatcher = red_qxl_get_dispatcher(qxl);
|
||||
dispatcher_set_opaque(dispatcher, worker);
|
||||
|
||||
worker->qxl = qxl;
|
||||
register_callbacks(dispatcher);
|
||||
if (worker->record_fd) {
|
||||
if (worker->record) {
|
||||
dispatcher_register_universal_handler(dispatcher, worker_dispatcher_record);
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user