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:
parent
aef22331b5
commit
37ff925d5d
7 changed files with 403 additions and 386 deletions
File diff suppressed because it is too large
Load diff
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
80
ui/vnc.c
80
ui/vnc.c
|
|
@ -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));
|
||||
|
|
@ -3266,19 +3253,19 @@ static void vnc_connect(VncDisplay *vd, QIOChannelSocket *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);
|
||||
|
|
|
|||
45
ui/vnc.h
45
ui/vnc.h
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue