ui/vnc: Introduce the VncWorker type

The worker thread copies data in VncState to avoid race, but some
data are too big to copy. Such data are held with pointers to avoid
the overhead to copy, but it requires tedious memory management and
makes them vulnerable to race.

Introduce the VncWorker type to contain all data shared without copying.
It allows allocating and freeing all shared data at once and shows that
the race with the worker thread needs to be taken care of when
accessing them.

Signed-off-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20250603-zlib-v3-2-20b857bd8d05@rsg.ci.i.u-tokyo.ac.jp>
This commit is contained in:
Akihiko Odaki 2025-06-03 18:18:29 +09:00 committed by Marc-André Lureau
parent aef22331b5
commit 37ff925d5d
7 changed files with 403 additions and 386 deletions

File diff suppressed because it is too large Load diff

View file

@ -46,23 +46,23 @@ void vnc_zlib_zfree(void *x, void *addr)
g_free(addr);
}
static void vnc_zlib_start(VncState *vs)
static void vnc_zlib_start(VncState *vs, VncWorker *worker)
{
buffer_reset(&vs->zlib->zlib);
buffer_reset(&worker->zlib.zlib);
// make the output buffer be the zlib buffer, so we can compress it later
vs->zlib->tmp = vs->output;
vs->output = vs->zlib->zlib;
worker->zlib.tmp = vs->output;
vs->output = worker->zlib.zlib;
}
static int vnc_zlib_stop(VncState *vs)
static int vnc_zlib_stop(VncState *vs, VncWorker *worker)
{
z_streamp zstream = &vs->zlib->stream;
z_streamp zstream = &worker->zlib.stream;
int previous_out;
// switch back to normal output/zlib buffers
vs->zlib->zlib = vs->output;
vs->output = vs->zlib->tmp;
worker->zlib.zlib = vs->output;
vs->output = worker->zlib.tmp;
// compress the zlib buffer
@ -76,7 +76,7 @@ static int vnc_zlib_stop(VncState *vs)
zstream->zalloc = vnc_zlib_zalloc;
zstream->zfree = vnc_zlib_zfree;
err = deflateInit2(zstream, vs->tight->compression, Z_DEFLATED,
err = deflateInit2(zstream, worker->tight.compression, Z_DEFLATED,
MAX_WBITS,
MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY);
@ -85,24 +85,24 @@ static int vnc_zlib_stop(VncState *vs)
return -1;
}
vs->zlib->level = vs->tight->compression;
worker->zlib.level = worker->tight.compression;
zstream->opaque = vs;
}
if (vs->tight->compression != vs->zlib->level) {
if (deflateParams(zstream, vs->tight->compression,
if (worker->tight.compression != worker->zlib.level) {
if (deflateParams(zstream, worker->tight.compression,
Z_DEFAULT_STRATEGY) != Z_OK) {
return -1;
}
vs->zlib->level = vs->tight->compression;
worker->zlib.level = worker->tight.compression;
}
// reserve memory in output buffer
buffer_reserve(&vs->output, vs->zlib->zlib.offset + 64);
buffer_reserve(&vs->output, worker->zlib.zlib.offset + 64);
// set pointers
zstream->next_in = vs->zlib->zlib.buffer;
zstream->avail_in = vs->zlib->zlib.offset;
zstream->next_in = worker->zlib.zlib.buffer;
zstream->avail_in = worker->zlib.zlib.offset;
zstream->next_out = vs->output.buffer + vs->output.offset;
zstream->avail_out = vs->output.capacity - vs->output.offset;
previous_out = zstream->avail_out;
@ -118,7 +118,8 @@ static int vnc_zlib_stop(VncState *vs)
return previous_out - zstream->avail_out;
}
int vnc_zlib_send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
int vnc_zlib_send_framebuffer_update(VncState *vs, VncWorker *worker,
int x, int y, int w, int h)
{
int old_offset, new_offset, bytes_written;
@ -129,9 +130,9 @@ int vnc_zlib_send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
vnc_write_s32(vs, 0);
// compress the stream
vnc_zlib_start(vs);
vnc_zlib_start(vs, worker);
vnc_raw_send_framebuffer_update(vs, x, y, w, h);
bytes_written = vnc_zlib_stop(vs);
bytes_written = vnc_zlib_stop(vs, worker);
if (bytes_written == -1)
return 0;
@ -145,10 +146,10 @@ int vnc_zlib_send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
return 1;
}
void vnc_zlib_clear(VncState *vs)
void vnc_zlib_clear(VncWorker *worker)
{
if (vs->zlib->stream.opaque) {
deflateEnd(&vs->zlib->stream);
if (worker->zlib.stream.opaque) {
deflateEnd(&worker->zlib.stream);
}
buffer_free(&vs->zlib->zlib);
buffer_free(&worker->zlib.zlib);
}

View file

@ -35,45 +35,45 @@ static const int bits_per_packed_pixel[] = {
};
static void vnc_zrle_start(VncState *vs)
static void vnc_zrle_start(VncState *vs, VncZrle *zrle)
{
buffer_reset(&vs->zrle->zrle);
buffer_reset(&zrle->zrle);
/* make the output buffer be the zlib buffer, so we can compress it later */
vs->zrle->tmp = vs->output;
vs->output = vs->zrle->zrle;
zrle->tmp = vs->output;
vs->output = zrle->zrle;
}
static void vnc_zrle_stop(VncState *vs)
static void vnc_zrle_stop(VncState *vs, VncZrle *zrle)
{
/* switch back to normal output/zlib buffers */
vs->zrle->zrle = vs->output;
vs->output = vs->zrle->tmp;
zrle->zrle = vs->output;
vs->output = zrle->tmp;
}
static void *zrle_convert_fb(VncState *vs, int x, int y, int w, int h,
int bpp)
static void *zrle_convert_fb(VncState *vs, VncZrle *zrle,
int x, int y, int w, int h, int bpp)
{
Buffer tmp;
buffer_reset(&vs->zrle->fb);
buffer_reserve(&vs->zrle->fb, w * h * bpp + bpp);
buffer_reset(&zrle->fb);
buffer_reserve(&zrle->fb, w * h * bpp + bpp);
tmp = vs->output;
vs->output = vs->zrle->fb;
vs->output = zrle->fb;
vnc_raw_send_framebuffer_update(vs, x, y, w, h);
vs->zrle->fb = vs->output;
zrle->fb = vs->output;
vs->output = tmp;
return vs->zrle->fb.buffer;
return zrle->fb.buffer;
}
static int zrle_compress_data(VncState *vs, int level)
static int zrle_compress_data(VncState *vs, VncZrle *zrle, int level)
{
z_streamp zstream = &vs->zrle->stream;
z_streamp zstream = &zrle->stream;
buffer_reset(&vs->zrle->zlib);
buffer_reset(&zrle->zlib);
if (zstream->opaque != vs) {
int err;
@ -93,13 +93,13 @@ static int zrle_compress_data(VncState *vs, int level)
}
/* reserve memory in output buffer */
buffer_reserve(&vs->zrle->zlib, vs->zrle->zrle.offset + 64);
buffer_reserve(&zrle->zlib, zrle->zrle.offset + 64);
/* set pointers */
zstream->next_in = vs->zrle->zrle.buffer;
zstream->avail_in = vs->zrle->zrle.offset;
zstream->next_out = vs->zrle->zlib.buffer;
zstream->avail_out = vs->zrle->zlib.capacity;
zstream->next_in = zrle->zrle.buffer;
zstream->avail_in = zrle->zrle.offset;
zstream->next_out = zrle->zlib.buffer;
zstream->avail_out = zrle->zlib.capacity;
zstream->data_type = Z_BINARY;
/* start encoding */
@ -108,8 +108,8 @@ static int zrle_compress_data(VncState *vs, int level)
return -1;
}
vs->zrle->zlib.offset = vs->zrle->zlib.capacity - zstream->avail_out;
return vs->zrle->zlib.offset;
zrle->zlib.offset = zrle->zlib.capacity - zstream->avail_out;
return zrle->zlib.offset;
}
/* Try to work out whether to use RLE and/or a palette. We do this by
@ -252,21 +252,21 @@ static void zrle_write_u8(VncState *vs, uint8_t value)
#undef ZRLE_COMPACT_PIXEL
#undef ZRLE_BPP
static int zrle_send_framebuffer_update(VncState *vs, int x, int y,
int w, int h)
static int zrle_send_framebuffer_update(VncState *vs, VncWorker *worker,
int x, int y, int w, int h)
{
bool be = vs->client_endian == G_BIG_ENDIAN;
size_t bytes;
int zywrle_level;
if (vs->zrle->type == VNC_ENCODING_ZYWRLE) {
if (!vs->vd->lossy || vs->tight->quality == (uint8_t)-1
|| vs->tight->quality == 9) {
if (worker->zrle.type == VNC_ENCODING_ZYWRLE) {
if (!vs->vd->lossy || worker->tight.quality == (uint8_t)-1
|| worker->tight.quality == 9) {
zywrle_level = 0;
vs->zrle->type = VNC_ENCODING_ZRLE;
} else if (vs->tight->quality < 3) {
worker->zrle.type = VNC_ENCODING_ZRLE;
} else if (worker->tight.quality < 3) {
zywrle_level = 3;
} else if (vs->tight->quality < 6) {
} else if (worker->tight.quality < 6) {
zywrle_level = 2;
} else {
zywrle_level = 1;
@ -275,25 +275,25 @@ static int zrle_send_framebuffer_update(VncState *vs, int x, int y,
zywrle_level = 0;
}
vnc_zrle_start(vs);
vnc_zrle_start(vs, &worker->zrle);
switch (vs->client_pf.bytes_per_pixel) {
case 1:
zrle_encode_8ne(vs, x, y, w, h, zywrle_level);
zrle_encode_8ne(vs, &worker->zrle, x, y, w, h, zywrle_level);
break;
case 2:
if (vs->client_pf.gmax > 0x1F) {
if (be) {
zrle_encode_16be(vs, x, y, w, h, zywrle_level);
zrle_encode_16be(vs, &worker->zrle, x, y, w, h, zywrle_level);
} else {
zrle_encode_16le(vs, x, y, w, h, zywrle_level);
zrle_encode_16le(vs, &worker->zrle, x, y, w, h, zywrle_level);
}
} else {
if (be) {
zrle_encode_15be(vs, x, y, w, h, zywrle_level);
zrle_encode_15be(vs, &worker->zrle, x, y, w, h, zywrle_level);
} else {
zrle_encode_15le(vs, x, y, w, h, zywrle_level);
zrle_encode_15le(vs, &worker->zrle, x, y, w, h, zywrle_level);
}
}
break;
@ -314,53 +314,55 @@ static int zrle_send_framebuffer_update(VncState *vs, int x, int y,
if ((fits_in_ls3bytes && !be) || (fits_in_ms3bytes && be)) {
if (be) {
zrle_encode_24abe(vs, x, y, w, h, zywrle_level);
zrle_encode_24abe(vs, &worker->zrle, x, y, w, h, zywrle_level);
} else {
zrle_encode_24ale(vs, x, y, w, h, zywrle_level);
zrle_encode_24ale(vs, &worker->zrle, x, y, w, h, zywrle_level);
}
} else if ((fits_in_ls3bytes && be) || (fits_in_ms3bytes && !be)) {
if (be) {
zrle_encode_24bbe(vs, x, y, w, h, zywrle_level);
zrle_encode_24bbe(vs, &worker->zrle, x, y, w, h, zywrle_level);
} else {
zrle_encode_24ble(vs, x, y, w, h, zywrle_level);
zrle_encode_24ble(vs, &worker->zrle, x, y, w, h, zywrle_level);
}
} else {
if (be) {
zrle_encode_32be(vs, x, y, w, h, zywrle_level);
zrle_encode_32be(vs, &worker->zrle, x, y, w, h, zywrle_level);
} else {
zrle_encode_32le(vs, x, y, w, h, zywrle_level);
zrle_encode_32le(vs, &worker->zrle, x, y, w, h, zywrle_level);
}
}
}
break;
}
vnc_zrle_stop(vs);
bytes = zrle_compress_data(vs, Z_DEFAULT_COMPRESSION);
vnc_framebuffer_update(vs, x, y, w, h, vs->zrle->type);
vnc_zrle_stop(vs, &worker->zrle);
bytes = zrle_compress_data(vs, &worker->zrle, Z_DEFAULT_COMPRESSION);
vnc_framebuffer_update(vs, x, y, w, h, worker->zrle.type);
vnc_write_u32(vs, bytes);
vnc_write(vs, vs->zrle->zlib.buffer, vs->zrle->zlib.offset);
vnc_write(vs, worker->zrle.zlib.buffer, worker->zrle.zlib.offset);
return 1;
}
int vnc_zrle_send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
int vnc_zrle_send_framebuffer_update(VncState *vs, VncWorker *worker,
int x, int y, int w, int h)
{
vs->zrle->type = VNC_ENCODING_ZRLE;
return zrle_send_framebuffer_update(vs, x, y, w, h);
worker->zrle.type = VNC_ENCODING_ZRLE;
return zrle_send_framebuffer_update(vs, worker, x, y, w, h);
}
int vnc_zywrle_send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
int vnc_zywrle_send_framebuffer_update(VncState *vs, VncWorker *worker,
int x, int y, int w, int h)
{
vs->zrle->type = VNC_ENCODING_ZYWRLE;
return zrle_send_framebuffer_update(vs, x, y, w, h);
worker->zrle.type = VNC_ENCODING_ZYWRLE;
return zrle_send_framebuffer_update(vs, worker, x, y, w, h);
}
void vnc_zrle_clear(VncState *vs)
void vnc_zrle_clear(VncWorker *worker)
{
if (vs->zrle->stream.opaque) {
deflateEnd(&vs->zrle->stream);
if (worker->zrle.stream.opaque) {
deflateEnd(&worker->zrle.stream);
}
buffer_free(&vs->zrle->zrle);
buffer_free(&vs->zrle->fb);
buffer_free(&vs->zrle->zlib);
buffer_free(&worker->zrle.zrle);
buffer_free(&worker->zrle.fb);
buffer_free(&worker->zrle.zlib);
}

View file

@ -62,16 +62,16 @@
#define ZRLE_ENCODE_TILE ZRLE_CONCAT2(zrle_encode_tile, ZRLE_ENCODE_SUFFIX)
#define ZRLE_WRITE_PALETTE ZRLE_CONCAT2(zrle_write_palette,ZRLE_ENCODE_SUFFIX)
static void ZRLE_ENCODE_TILE(VncState *vs, ZRLE_PIXEL *data, int w, int h,
int zywrle_level);
static void ZRLE_ENCODE_TILE(VncState *vs, VncZrle *zrle, ZRLE_PIXEL *data,
int w, int h, int zywrle_level);
#if ZRLE_BPP != 8
#include "vnc-enc-zywrle-template.c"
#endif
static void ZRLE_ENCODE(VncState *vs, int x, int y, int w, int h,
int zywrle_level)
static void ZRLE_ENCODE(VncState *vs, VncZrle *zrle,
int x, int y, int w, int h, int zywrle_level)
{
int ty;
@ -87,16 +87,16 @@ static void ZRLE_ENCODE(VncState *vs, int x, int y, int w, int h,
tw = MIN(VNC_ZRLE_TILE_WIDTH, x + w - tx);
buf = zrle_convert_fb(vs, tx, ty, tw, th, ZRLE_BPP);
ZRLE_ENCODE_TILE(vs, buf, tw, th, zywrle_level);
buf = zrle_convert_fb(vs, zrle, tx, ty, tw, th, ZRLE_BPP);
ZRLE_ENCODE_TILE(vs, zrle, buf, tw, th, zywrle_level);
}
}
}
static void ZRLE_ENCODE_TILE(VncState *vs, ZRLE_PIXEL *data, int w, int h,
int zywrle_level)
static void ZRLE_ENCODE_TILE(VncState *vs, VncZrle *zrle, ZRLE_PIXEL *data,
int w, int h, int zywrle_level)
{
VncPalette *palette = &vs->zrle->palette;
VncPalette *palette = &zrle->palette;
int runs = 0;
int single_pixels = 0;
@ -236,7 +236,7 @@ static void ZRLE_ENCODE_TILE(VncState *vs, ZRLE_PIXEL *data, int w, int h,
#if ZRLE_BPP != 8
if (zywrle_level > 0 && !(zywrle_level & 0x80)) {
ZYWRLE_ANALYZE(data, data, w, h, w, zywrle_level, vs->zywrle.buf);
ZRLE_ENCODE_TILE(vs, data, w, h, zywrle_level | 0x80);
ZRLE_ENCODE_TILE(vs, zrle, data, w, h, zywrle_level | 0x80);
}
else
#endif

View file

@ -185,14 +185,10 @@ static void vnc_async_encoding_start(VncState *orig, VncState *local)
local->vnc_encoding = orig->vnc_encoding;
local->features = orig->features;
local->vd = orig->vd;
local->lossy_rect = orig->lossy_rect;
local->write_pixels = orig->write_pixels;
local->client_pf = orig->client_pf;
local->client_endian = orig->client_endian;
local->tight = orig->tight;
local->zlib = orig->zlib;
local->hextile = orig->hextile;
local->zrle = orig->zrle;
local->client_width = orig->client_width;
local->client_height = orig->client_height;
}
@ -200,11 +196,7 @@ static void vnc_async_encoding_start(VncState *orig, VncState *local)
static void vnc_async_encoding_end(VncState *orig, VncState *local)
{
buffer_free(&local->output);
orig->tight = local->tight;
orig->zlib = local->zlib;
orig->hextile = local->hextile;
orig->zrle = local->zrle;
orig->lossy_rect = local->lossy_rect;
}
static bool vnc_worker_clamp_rect(VncState *vs, VncJob *job, VncRect *rect)
@ -237,6 +229,7 @@ static bool vnc_worker_clamp_rect(VncState *vs, VncJob *job, VncRect *rect)
static int vnc_worker_thread_loop(VncJobQueue *queue)
{
VncConnection *vc;
VncJob *job;
VncRectEntry *entry, *tmp;
VncState vs = {};
@ -256,6 +249,7 @@ static int vnc_worker_thread_loop(VncJobQueue *queue)
}
assert(job->vs->magic == VNC_MAGIC);
vc = container_of(job->vs, VncConnection, vs);
vnc_lock_output(job->vs);
if (job->vs->ioc == NULL || job->vs->abort == true) {
@ -295,7 +289,8 @@ static int vnc_worker_thread_loop(VncJobQueue *queue)
}
if (vnc_worker_clamp_rect(&vs, job, &entry->rect)) {
n = vnc_send_framebuffer_update(&vs, entry->rect.x, entry->rect.y,
n = vnc_send_framebuffer_update(&vs, &vc->worker,
entry->rect.x, entry->rect.y,
entry->rect.w, entry->rect.h);
if (n >= 0) {

View file

@ -56,11 +56,6 @@
#include "io/dns-resolver.h"
#include "monitor/monitor.h"
typedef struct VncConnection {
VncState vs;
VncZlib zlib;
} VncConnection;
#define VNC_REFRESH_INTERVAL_BASE GUI_REFRESH_INTERVAL_DEFAULT
#define VNC_REFRESH_INTERVAL_INC 50
#define VNC_REFRESH_INTERVAL_MAX GUI_REFRESH_INTERVAL_IDLE
@ -951,29 +946,30 @@ int vnc_raw_send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
return 1;
}
int vnc_send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
int vnc_send_framebuffer_update(VncState *vs, VncWorker *worker,
int x, int y, int w, int h)
{
int n = 0;
switch(vs->vnc_encoding) {
case VNC_ENCODING_ZLIB:
n = vnc_zlib_send_framebuffer_update(vs, x, y, w, h);
n = vnc_zlib_send_framebuffer_update(vs, worker, x, y, w, h);
break;
case VNC_ENCODING_HEXTILE:
vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_HEXTILE);
n = vnc_hextile_send_framebuffer_update(vs, x, y, w, h);
break;
case VNC_ENCODING_TIGHT:
n = vnc_tight_send_framebuffer_update(vs, x, y, w, h);
n = vnc_tight_send_framebuffer_update(vs, worker, x, y, w, h);
break;
case VNC_ENCODING_TIGHT_PNG:
n = vnc_tight_png_send_framebuffer_update(vs, x, y, w, h);
n = vnc_tight_png_send_framebuffer_update(vs, worker, x, y, w, h);
break;
case VNC_ENCODING_ZRLE:
n = vnc_zrle_send_framebuffer_update(vs, x, y, w, h);
n = vnc_zrle_send_framebuffer_update(vs, worker, x, y, w, h);
break;
case VNC_ENCODING_ZYWRLE:
n = vnc_zywrle_send_framebuffer_update(vs, x, y, w, h);
n = vnc_zywrle_send_framebuffer_update(vs, worker, x, y, w, h);
break;
default:
vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_RAW);
@ -1311,7 +1307,7 @@ static void vnc_disconnect_start(VncState *vs)
void vnc_disconnect_finish(VncState *vs)
{
int i;
VncConnection *vc = container_of(vs, VncConnection, vs);
trace_vnc_client_disconnect_finish(vs, vs->ioc);
@ -1325,9 +1321,9 @@ void vnc_disconnect_finish(VncState *vs)
qapi_free_VncClientInfo(vs->info);
vnc_zlib_clear(vs);
vnc_tight_clear(vs);
vnc_zrle_clear(vs);
vnc_zlib_clear(&vc->worker);
vnc_tight_clear(&vc->worker);
vnc_zrle_clear(&vc->worker);
#ifdef CONFIG_VNC_SASL
vnc_sasl_client_cleanup(vs);
@ -1355,19 +1351,12 @@ void vnc_disconnect_finish(VncState *vs)
}
buffer_free(&vs->jobs_buffer);
for (i = 0; i < VNC_STAT_ROWS; ++i) {
g_free(vs->lossy_rect[i]);
}
g_free(vs->lossy_rect);
object_unref(OBJECT(vs->ioc));
vs->ioc = NULL;
object_unref(OBJECT(vs->sioc));
vs->sioc = NULL;
vs->magic = 0;
g_free(vs->zrle);
g_free(vs->tight);
g_free(container_of(vs, VncConnection, vs));
g_free(vc);
}
size_t vnc_client_io_error(VncState *vs, ssize_t ret, Error *err)
@ -2131,13 +2120,14 @@ static void send_xvp_message(VncState *vs, int code)
static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
{
VncConnection *vc = container_of(vs, VncConnection, vs);
int i;
unsigned int enc = 0;
vs->features = 0;
vs->vnc_encoding = 0;
vs->tight->compression = 9;
vs->tight->quality = -1; /* Lossless by default */
vc->worker.tight.compression = 9;
vc->worker.tight.quality = -1; /* Lossless by default */
vs->absolute = -1;
/*
@ -2225,11 +2215,11 @@ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
vnc_server_cut_text_caps(vs);
break;
case VNC_ENCODING_COMPRESSLEVEL0 ... VNC_ENCODING_COMPRESSLEVEL0 + 9:
vs->tight->compression = (enc & 0x0F);
vc->worker.tight.compression = (enc & 0x0F);
break;
case VNC_ENCODING_QUALITYLEVEL0 ... VNC_ENCODING_QUALITYLEVEL0 + 9:
if (vs->vd->lossy) {
vs->tight->quality = (enc & 0x0F);
vc->worker.tight.quality = (enc & 0x0F);
}
break;
default:
@ -2958,7 +2948,7 @@ static VncRectStat *vnc_stat_rect(VncDisplay *vd, int x, int y)
return &vs->stats[y / VNC_STAT_RECT][x / VNC_STAT_RECT];
}
void vnc_sent_lossy_rect(VncState *vs, int x, int y, int w, int h)
void vnc_sent_lossy_rect(VncWorker *worker, int x, int y, int w, int h)
{
int i, j;
@ -2969,7 +2959,7 @@ void vnc_sent_lossy_rect(VncState *vs, int x, int y, int w, int h)
for (j = y; j <= h; j++) {
for (i = x; i <= w; i++) {
vs->lossy_rect[j][i] = 1;
worker->lossy_rect[j][i] = 1;
}
}
}
@ -2985,6 +2975,7 @@ static int vnc_refresh_lossy_rect(VncDisplay *vd, int x, int y)
x = QEMU_ALIGN_DOWN(x, VNC_STAT_RECT);
QTAILQ_FOREACH(vs, &vd->clients, next) {
VncConnection *vc = container_of(vs, VncConnection, vs);
int j;
/* kernel send buffers are full -> refresh later */
@ -2992,11 +2983,11 @@ static int vnc_refresh_lossy_rect(VncDisplay *vd, int x, int y)
continue;
}
if (!vs->lossy_rect[sty][stx]) {
if (!vc->worker.lossy_rect[sty][stx]) {
continue;
}
vs->lossy_rect[sty][stx] = 0;
vc->worker.lossy_rect[sty][stx] = 0;
for (j = 0; j < VNC_STAT_RECT; ++j) {
bitmap_set(vs->dirty[y + j],
x / VNC_DIRTY_PIXELS_PER_BIT,
@ -3249,12 +3240,8 @@ static void vnc_connect(VncDisplay *vd, QIOChannelSocket *sioc,
VncConnection *vc = g_new0(VncConnection, 1);
VncState *vs = &vc->vs;
bool first_client = QTAILQ_EMPTY(&vd->clients);
int i;
trace_vnc_client_connect(vs, sioc);
vs->zlib = &vc->zlib;
vs->zrle = g_new0(VncZrle, 1);
vs->tight = g_new0(VncTight, 1);
vs->magic = VNC_MAGIC;
vs->sioc = sioc;
object_ref(OBJECT(vs->sioc));
@ -3262,23 +3249,23 @@ static void vnc_connect(VncDisplay *vd, QIOChannelSocket *sioc,
object_ref(OBJECT(vs->ioc));
vs->vd = vd;
buffer_init(&vs->input, "vnc-input/%p", sioc);
buffer_init(&vs->output, "vnc-output/%p", sioc);
buffer_init(&vs->jobs_buffer, "vnc-jobs_buffer/%p", sioc);
buffer_init(&vs->input, "vnc-input/%p", sioc);
buffer_init(&vs->output, "vnc-output/%p", sioc);
buffer_init(&vs->jobs_buffer, "vnc-jobs_buffer/%p", sioc);
buffer_init(&vs->tight->tight, "vnc-tight/%p", sioc);
buffer_init(&vs->tight->zlib, "vnc-tight-zlib/%p", sioc);
buffer_init(&vs->tight->gradient, "vnc-tight-gradient/%p", sioc);
buffer_init(&vc->worker.tight.tight, "vnc-tight/%p", sioc);
buffer_init(&vc->worker.tight.zlib, "vnc-tight-zlib/%p", sioc);
buffer_init(&vc->worker.tight.gradient, "vnc-tight-gradient/%p", sioc);
#ifdef CONFIG_VNC_JPEG
buffer_init(&vs->tight->jpeg, "vnc-tight-jpeg/%p", sioc);
buffer_init(&vc->worker.tight.jpeg, "vnc-tight-jpeg/%p", sioc);
#endif
#ifdef CONFIG_PNG
buffer_init(&vs->tight->png, "vnc-tight-png/%p", sioc);
buffer_init(&vc->worker.tight.png, "vnc-tight-png/%p", sioc);
#endif
buffer_init(&vc->zlib.zlib, "vnc-zlib/%p", sioc);
buffer_init(&vs->zrle->zrle, "vnc-zrle/%p", sioc);
buffer_init(&vs->zrle->fb, "vnc-zrle-fb/%p", sioc);
buffer_init(&vs->zrle->zlib, "vnc-zrle-zlib/%p", sioc);
buffer_init(&vc->worker.zlib.zlib, "vnc-zlib/%p", sioc);
buffer_init(&vc->worker.zrle.zrle, "vnc-zrle/%p", sioc);
buffer_init(&vc->worker.zrle.fb, "vnc-zrle-fb/%p", sioc);
buffer_init(&vc->worker.zrle.zlib, "vnc-zrle-zlib/%p", sioc);
if (skipauth) {
vs->auth = VNC_AUTH_NONE;
@ -3295,11 +3282,6 @@ static void vnc_connect(VncDisplay *vd, QIOChannelSocket *sioc,
VNC_DEBUG("Client sioc=%p ws=%d auth=%d subauth=%d\n",
sioc, websocket, vs->auth, vs->subauth);
vs->lossy_rect = g_malloc0(VNC_STAT_ROWS * sizeof (*vs->lossy_rect));
for (i = 0; i < VNC_STAT_ROWS; ++i) {
vs->lossy_rect[i] = g_new0(uint8_t, VNC_STAT_COLS);
}
VNC_DEBUG("New client on socket %p\n", vs->sioc);
update_displaychangelistener(&vd->dcl, VNC_REFRESH_INTERVAL_BASE);
qio_channel_set_blocking(vs->ioc, false, NULL);

View file

@ -272,8 +272,6 @@ struct VncState
gboolean disconnecting;
DECLARE_BITMAP(dirty[VNC_MAX_HEIGHT], VNC_DIRTY_BITS);
uint8_t **lossy_rect; /* Not an Array to avoid costly memcpy in
* vnc-jobs-async.c */
VncDisplay *vd;
VncStateUpdate update; /* Most recent pending request from client */
@ -341,10 +339,7 @@ struct VncState
/* Encoding specific, if you add something here, don't forget to
* update vnc_async_encoding_start()
*/
VncTight *tight;
VncZlib *zlib;
VncHextile hextile;
VncZrle *zrle;
VncZywrle zywrle;
Notifier mouse_mode_notifier;
@ -356,6 +351,19 @@ struct VncState
QTAILQ_ENTRY(VncState) next;
};
typedef struct VncWorker {
uint8_t lossy_rect[VNC_STAT_ROWS][VNC_STAT_COLS];
VncTight tight;
VncZlib zlib;
VncZrle zrle;
} VncWorker;
typedef struct VncConnection {
VncState vs;
VncWorker worker;
} VncConnection;
/*****************************************************************************
*
@ -602,10 +610,11 @@ int vnc_server_fb_stride(VncDisplay *vd);
void vnc_convert_pixel(VncState *vs, uint8_t *buf, uint32_t v);
double vnc_update_freq(VncState *vs, int x, int y, int w, int h);
void vnc_sent_lossy_rect(VncState *vs, int x, int y, int w, int h);
void vnc_sent_lossy_rect(VncWorker *worker, int x, int y, int w, int h);
/* Encodings */
int vnc_send_framebuffer_update(VncState *vs, int x, int y, int w, int h);
int vnc_send_framebuffer_update(VncState *vs, VncWorker *worker,
int x, int y, int w, int h);
int vnc_raw_send_framebuffer_update(VncState *vs, int x, int y, int w, int h);
@ -615,17 +624,21 @@ void vnc_hextile_set_pixel_conversion(VncState *vs, int generic);
void *vnc_zlib_zalloc(void *x, unsigned items, unsigned size);
void vnc_zlib_zfree(void *x, void *addr);
int vnc_zlib_send_framebuffer_update(VncState *vs, int x, int y, int w, int h);
void vnc_zlib_clear(VncState *vs);
int vnc_zlib_send_framebuffer_update(VncState *vs, VncWorker *worker,
int x, int y, int w, int h);
void vnc_zlib_clear(VncWorker *worker);
int vnc_tight_send_framebuffer_update(VncState *vs, int x, int y, int w, int h);
int vnc_tight_png_send_framebuffer_update(VncState *vs, int x, int y,
int w, int h);
void vnc_tight_clear(VncState *vs);
int vnc_tight_send_framebuffer_update(VncState *vs, VncWorker *worker,
int x, int y, int w, int h);
int vnc_tight_png_send_framebuffer_update(VncState *vs, VncWorker *worker,
int x, int y, int w, int h);
void vnc_tight_clear(VncWorker *worker);
int vnc_zrle_send_framebuffer_update(VncState *vs, int x, int y, int w, int h);
int vnc_zywrle_send_framebuffer_update(VncState *vs, int x, int y, int w, int h);
void vnc_zrle_clear(VncState *vs);
int vnc_zrle_send_framebuffer_update(VncState *vs, VncWorker *worker,
int x, int y, int w, int h);
int vnc_zywrle_send_framebuffer_update(VncState *vs, VncWorker *worker,
int x, int y, int w, int h);
void vnc_zrle_clear(VncWorker *worker);
/* vnc-clipboard.c */
void vnc_server_cut_text_caps(VncState *vs);