From nobody Sat Nov 15 18:49:36 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=reject dis=none) header.from=rsg.ci.i.u-tokyo.ac.jp Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1748701324069910.3666510442666; Sat, 31 May 2025 07:22:04 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1uLN5L-0002mN-AE; Sat, 31 May 2025 10:21:19 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uLN5I-0002kW-I1 for qemu-devel@nongnu.org; Sat, 31 May 2025 10:21:16 -0400 Received: from www3579.sakura.ne.jp ([49.212.243.89]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uLN5D-0007nP-Bj for qemu-devel@nongnu.org; Sat, 31 May 2025 10:21:16 -0400 Received: from [192.168.10.111] (p865013-ipoe.ipoe.ocn.ne.jp [153.242.222.12]) (authenticated bits=0) by www3579.sakura.ne.jp (8.16.1/8.16.1) with ESMTPSA id 54VEKrPZ069146 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO); Sat, 31 May 2025 23:20:59 +0900 (JST) (envelope-from odaki@rsg.ci.i.u-tokyo.ac.jp) DKIM-Signature: a=rsa-sha256; bh=N3zRNOnIY0rmK69A6CJyDWRJa8HBaTriZ18mL56dbOs=; c=relaxed/relaxed; d=rsg.ci.i.u-tokyo.ac.jp; h=From:Date:Subject:Message-Id:To; s=rs20250326; t=1748701259; v=1; b=AiE8jpzskrTWVCDQq6FtVJ0/jrtU1BWX3F17rcgXeK9iQGvfKI0CR2vRgHuQ0ATb T+zQRYqXKRaeEwTqVl1xNYDlJPCxuHTm+CJhOSkIsziIa3xlxHKpwTCZ8CXQWmHX 1aUqoN8HVzRJnRUSrgSBqPH6ieSxAq/++2jWjihNX4TX0d6cQNUYhLMUGQZlQHaR 4wLezmgIF290fIZX/0TdrmDlJPfBeoQWBPdCA7AlK6V9rijB7cAWaugOegEoeWu8 bhs7bnhDrYvZjSl5pKBrXQ/N+nwI3VeyC6XlnNFXuS8RimN1NKhzawC4Lj8pGQex TB18xVhZxbQJ7DCbMQMORQ== From: Akihiko Odaki Date: Sat, 31 May 2025 23:20:41 +0900 Subject: [PATCH v2 1/2] ui/vnc: Introduce the VncWorker type MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250531-zlib-v2-1-b75c4b4769e1@rsg.ci.i.u-tokyo.ac.jp> References: <20250531-zlib-v2-0-b75c4b4769e1@rsg.ci.i.u-tokyo.ac.jp> In-Reply-To: <20250531-zlib-v2-0-b75c4b4769e1@rsg.ci.i.u-tokyo.ac.jp> To: qemu-devel@nongnu.org Cc: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , devel@daynix.com, Akihiko Odaki , =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= X-Mailer: b4 0.15-dev-edae6 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=49.212.243.89; envelope-from=odaki@rsg.ci.i.u-tokyo.ac.jp; helo=www3579.sakura.ne.jp X-Spam_score_int: 3 X-Spam_score: 0.3 X-Spam_bar: / X-Spam_report: (0.3 / 5.0 requ) BAYES_00=-1.9, DKIM_INVALID=0.1, DKIM_SIGNED=0.1, PDS_OTHER_BAD_TLD=1.997, RCVD_IN_VALIDITY_CERTIFIED_BLOCKED=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZM-MESSAGEID: 1748701325569116600 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 Reviewed-by: Philippe Mathieu-Daud=C3=A9 --- ui/vnc.h | 12 +- ui/vnc-enc-tight.c | 341 ++++++++++++++++++++++++++--------------------= ---- ui/vnc-enc-zlib.c | 10 +- ui/vnc-enc-zrle.c | 69 +++++----- ui/vnc-jobs.c | 7 +- ui/vnc.c | 56 ++++----- ui/vnc-enc-zrle.c.inc | 2 +- 7 files changed, 245 insertions(+), 252 deletions(-) diff --git a/ui/vnc.h b/ui/vnc.h index acc53a2cc114..1dc76c270c35 100644 --- a/ui/vnc.h +++ b/ui/vnc.h @@ -261,6 +261,13 @@ typedef enum { =20 #define VNC_MAGIC ((uint64_t)0x05b3f069b3d204bb) =20 +typedef struct VncWorker { + uint8_t lossy_rect[VNC_STAT_ROWS][VNC_STAT_COLS]; + + VncTight tight; + VncZrle zrle; +} VncWorker; + struct VncState { uint64_t magic; @@ -270,8 +277,7 @@ struct VncState gboolean disconnecting; =20 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 */ + VncWorker *worker; =20 VncDisplay *vd; VncStateUpdate update; /* Most recent pending request from client */ @@ -339,10 +345,8 @@ 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; =20 Notifier mouse_mode_notifier; diff --git a/ui/vnc-enc-tight.c b/ui/vnc-enc-tight.c index 41f559eb837e..a8d06a125044 100644 --- a/ui/vnc-enc-tight.c +++ b/ui/vnc-enc-tight.c @@ -116,7 +116,7 @@ static int send_png_rect(VncState *vs, int x, int y, in= t w, int h, =20 static bool tight_can_send_png_rect(VncState *vs, int w, int h) { - if (vs->tight->type !=3D VNC_ENCODING_TIGHT_PNG) { + if (vs->worker->tight.type !=3D VNC_ENCODING_TIGHT_PNG) { return false; } =20 @@ -144,7 +144,7 @@ tight_detect_smooth_image24(VncState *vs, int w, int h) int pixels =3D 0; int pix, left[3]; unsigned int errors; - unsigned char *buf =3D vs->tight->tight.buffer; + unsigned char *buf =3D vs->worker->tight.tight.buffer; =20 /* * If client is big-endian, color samples begin from the second @@ -215,7 +215,7 @@ tight_detect_smooth_image24(VncState *vs, int w, int h) int pixels =3D 0; \ int sample, sum, left[3]; \ unsigned int errors; \ - unsigned char *buf =3D vs->tight->tight.buffer; = \ + unsigned char *buf =3D vs->worker->tight.tight.buffer; \ \ endian =3D 0; /* FIXME */ \ \ @@ -296,8 +296,8 @@ static int tight_detect_smooth_image(VncState *vs, int w, int h) { unsigned int errors; - int compression =3D vs->tight->compression; - int quality =3D vs->tight->quality; + int compression =3D vs->worker->tight.compression; + int quality =3D vs->worker->tight.quality; =20 if (!vs->vd->lossy) { return 0; @@ -309,7 +309,7 @@ tight_detect_smooth_image(VncState *vs, int w, int h) return 0; } =20 - if (vs->tight->quality !=3D (uint8_t)-1) { + if (vs->worker->tight.quality !=3D (uint8_t)-1) { if (w * h < VNC_TIGHT_JPEG_MIN_RECT_SIZE) { return 0; } @@ -320,9 +320,9 @@ tight_detect_smooth_image(VncState *vs, int w, int h) } =20 if (vs->client_pf.bytes_per_pixel =3D=3D 4) { - if (vs->tight->pixel24) { + if (vs->worker->tight.pixel24) { errors =3D tight_detect_smooth_image24(vs, w, h); - if (vs->tight->quality !=3D (uint8_t)-1) { + if (vs->worker->tight.quality !=3D (uint8_t)-1) { return (errors < tight_conf[quality].jpeg_threshold24); } return (errors < tight_conf[compression].gradient_threshold24); @@ -352,7 +352,7 @@ tight_detect_smooth_image(VncState *vs, int w, int h) uint##bpp##_t c0, c1, ci; \ int i, n0, n1; \ \ - data =3D (uint##bpp##_t *)vs->tight->tight.buffer; \ + data =3D (uint##bpp##_t *)vs->worker->tight.tight.buffer; \ \ c0 =3D data[0]; \ i =3D 1; \ @@ -421,11 +421,12 @@ static int tight_fill_palette(VncState *vs, int x, in= t y, size_t count, uint32_t *bg, uint32_t *fg, VncPalette *palette) { + uint8_t compression =3D vs->worker->tight.compression; int max; =20 - max =3D count / tight_conf[vs->tight->compression].idx_max_colors_divi= sor; + max =3D count / tight_conf[compression].idx_max_colors_divisor; if (max < 2 && - count >=3D tight_conf[vs->tight->compression].mono_min_rect_size) { + count >=3D tight_conf[compression].mono_min_rect_size) { max =3D 2; } if (max >=3D 256) { @@ -558,7 +559,7 @@ tight_filter_gradient24(VncState *vs, uint8_t *buf, int= w, int h) int x, y, c; =20 buf32 =3D (uint32_t *)buf; - memset(vs->tight->gradient.buffer, 0, w * 3 * sizeof(int)); + memset(vs->worker->tight.gradient.buffer, 0, w * 3 * sizeof(int)); =20 if (1 /* FIXME */) { shift[0] =3D vs->client_pf.rshift; @@ -575,7 +576,7 @@ tight_filter_gradient24(VncState *vs, uint8_t *buf, int= w, int h) upper[c] =3D 0; here[c] =3D 0; } - prev =3D (int *)vs->tight->gradient.buffer; + prev =3D (int *)vs->worker->tight.gradient.buffer; for (x =3D 0; x < w; x++) { pix32 =3D *buf32++; for (c =3D 0; c < 3; c++) { @@ -602,64 +603,64 @@ tight_filter_gradient24(VncState *vs, uint8_t *buf, i= nt w, int h) * ``Gradient'' filter for other color depths. */ =20 -#define DEFINE_GRADIENT_FILTER_FUNCTION(bpp) \ - \ - static void \ - tight_filter_gradient##bpp(VncState *vs, uint##bpp##_t *buf, \ - int w, int h) { \ - uint##bpp##_t pix, diff; \ - bool endian; \ - int *prev; \ - int max[3], shift[3]; \ - int here[3], upper[3], left[3], upperleft[3]; \ - int prediction; \ - int x, y, c; \ - \ - memset(vs->tight->gradient.buffer, 0, w * 3 * sizeof(int)); \ - \ - endian =3D 0; /* FIXME */ \ - \ - max[0] =3D vs->client_pf.rmax; \ - max[1] =3D vs->client_pf.gmax; \ - max[2] =3D vs->client_pf.bmax; \ - shift[0] =3D vs->client_pf.rshift; \ - shift[1] =3D vs->client_pf.gshift; \ - shift[2] =3D vs->client_pf.bshift; \ - \ - for (y =3D 0; y < h; y++) { \ - for (c =3D 0; c < 3; c++) { \ - upper[c] =3D 0; \ - here[c] =3D 0; \ - } \ - prev =3D (int *)vs->tight->gradient.buffer; = \ - for (x =3D 0; x < w; x++) { \ - pix =3D *buf; \ - if (endian) { \ - pix =3D bswap##bpp(pix); \ - } \ - diff =3D 0; \ - for (c =3D 0; c < 3; c++) { \ - upperleft[c] =3D upper[c]; \ - left[c] =3D here[c]; \ - upper[c] =3D *prev; \ - here[c] =3D (int)(pix >> shift[c] & max[c]); \ - *prev++ =3D here[c]; \ - \ - prediction =3D left[c] + upper[c] - upperleft[c]; \ - if (prediction < 0) { \ - prediction =3D 0; \ - } else if (prediction > max[c]) { \ - prediction =3D max[c]; \ - } \ - diff |=3D ((here[c] - prediction) & max[c]) \ - << shift[c]; \ - } \ - if (endian) { \ - diff =3D bswap##bpp(diff); \ - } \ - *buf++ =3D diff; \ - } \ - } \ +#define DEFINE_GRADIENT_FILTER_FUNCTION(bpp) = \ + = \ + static void = \ + tight_filter_gradient##bpp(VncState *vs, uint##bpp##_t *buf, = \ + int w, int h) { = \ + uint##bpp##_t pix, diff; = \ + bool endian; = \ + int *prev; = \ + int max[3], shift[3]; = \ + int here[3], upper[3], left[3], upperleft[3]; = \ + int prediction; = \ + int x, y, c; = \ + = \ + memset(vs->worker->tight.gradient.buffer, 0, w * 3 * sizeof(int));= \ + = \ + endian =3D 0; /* FIXME */ = \ + = \ + max[0] =3D vs->client_pf.rmax; = \ + max[1] =3D vs->client_pf.gmax; = \ + max[2] =3D vs->client_pf.bmax; = \ + shift[0] =3D vs->client_pf.rshift; = \ + shift[1] =3D vs->client_pf.gshift; = \ + shift[2] =3D vs->client_pf.bshift; = \ + = \ + for (y =3D 0; y < h; y++) { = \ + for (c =3D 0; c < 3; c++) { = \ + upper[c] =3D 0; = \ + here[c] =3D 0; = \ + } = \ + prev =3D (int *)vs->worker->tight.gradient.buffer; = \ + for (x =3D 0; x < w; x++) { = \ + pix =3D *buf; = \ + if (endian) { = \ + pix =3D bswap##bpp(pix); = \ + } = \ + diff =3D 0; = \ + for (c =3D 0; c < 3; c++) { = \ + upperleft[c] =3D upper[c]; = \ + left[c] =3D here[c]; = \ + upper[c] =3D *prev; = \ + here[c] =3D (int)(pix >> shift[c] & max[c]); = \ + *prev++ =3D here[c]; = \ + = \ + prediction =3D left[c] + upper[c] - upperleft[c]; = \ + if (prediction < 0) { = \ + prediction =3D 0; = \ + } else if (prediction > max[c]) { = \ + prediction =3D max[c]; = \ + } = \ + diff |=3D ((here[c] - prediction) & max[c]) = \ + << shift[c]; = \ + } = \ + if (endian) { = \ + diff =3D bswap##bpp(diff); = \ + } = \ + *buf++ =3D diff; = \ + } = \ + } = \ } =20 DEFINE_GRADIENT_FILTER_FUNCTION(16) @@ -785,7 +786,7 @@ static void extend_solid_area(VncState *vs, int x, int = y, int w, int h, static int tight_init_stream(VncState *vs, int stream_id, int level, int strategy) { - z_streamp zstream =3D &vs->tight->stream[stream_id]; + z_streamp zstream =3D &vs->worker->tight.stream[stream_id]; =20 if (zstream->opaque =3D=3D NULL) { int err; @@ -803,15 +804,15 @@ static int tight_init_stream(VncState *vs, int stream= _id, return -1; } =20 - vs->tight->levels[stream_id] =3D level; + vs->worker->tight.levels[stream_id] =3D level; zstream->opaque =3D vs; } =20 - if (vs->tight->levels[stream_id] !=3D level) { + if (vs->worker->tight.levels[stream_id] !=3D level) { if (deflateParams(zstream, level, strategy) !=3D Z_OK) { return -1; } - vs->tight->levels[stream_id] =3D level; + vs->worker->tight.levels[stream_id] =3D level; } return 0; } @@ -839,11 +840,12 @@ static void tight_send_compact_size(VncState *vs, siz= e_t len) static int tight_compress_data(VncState *vs, int stream_id, size_t bytes, int level, int strategy) { - z_streamp zstream =3D &vs->tight->stream[stream_id]; + VncTight *tight =3D &vs->worker->tight; + z_streamp zstream =3D &vs->worker->tight.stream[stream_id]; int previous_out; =20 if (bytes < VNC_TIGHT_MIN_TO_COMPRESS) { - vnc_write(vs, vs->tight->tight.buffer, vs->tight->tight.offset); + vnc_write(vs, tight->tight.buffer, tight->tight.offset); return bytes; } =20 @@ -852,13 +854,13 @@ static int tight_compress_data(VncState *vs, int stre= am_id, size_t bytes, } =20 /* reserve memory in output buffer */ - buffer_reserve(&vs->tight->zlib, bytes + 64); + buffer_reserve(&tight->zlib, bytes + 64); =20 /* set pointers */ - zstream->next_in =3D vs->tight->tight.buffer; - zstream->avail_in =3D vs->tight->tight.offset; - zstream->next_out =3D vs->tight->zlib.buffer + vs->tight->zlib.offset; - zstream->avail_out =3D vs->tight->zlib.capacity - vs->tight->zlib.offs= et; + zstream->next_in =3D tight->tight.buffer; + zstream->avail_in =3D tight->tight.offset; + zstream->next_out =3D tight->zlib.buffer + tight->zlib.offset; + zstream->avail_out =3D tight->zlib.capacity - tight->zlib.offset; previous_out =3D zstream->avail_out; zstream->data_type =3D Z_BINARY; =20 @@ -868,14 +870,14 @@ static int tight_compress_data(VncState *vs, int stre= am_id, size_t bytes, return -1; } =20 - vs->tight->zlib.offset =3D vs->tight->zlib.capacity - zstream->avail_o= ut; + tight->zlib.offset =3D tight->zlib.capacity - zstream->avail_out; /* ...how much data has actually been produced by deflate() */ bytes =3D previous_out - zstream->avail_out; =20 tight_send_compact_size(vs, bytes); - vnc_write(vs, vs->tight->zlib.buffer, bytes); + vnc_write(vs, tight->zlib.buffer, bytes); =20 - buffer_reset(&vs->tight->zlib); + buffer_reset(&tight->zlib); =20 return bytes; } @@ -916,6 +918,7 @@ static void tight_pack24(VncState *vs, uint8_t *buf, si= ze_t count, size_t *ret) =20 static int send_full_color_rect(VncState *vs, int x, int y, int w, int h) { + int level =3D tight_conf[vs->worker->tight.compression].raw_zlib_level; int stream =3D 0; ssize_t bytes; =20 @@ -927,16 +930,15 @@ static int send_full_color_rect(VncState *vs, int x, = int y, int w, int h) =20 vnc_write_u8(vs, stream << 4); /* no flushing, no filter */ =20 - if (vs->tight->pixel24) { - tight_pack24(vs, vs->tight->tight.buffer, w * h, - &vs->tight->tight.offset); + if (vs->worker->tight.pixel24) { + tight_pack24(vs, vs->worker->tight.tight.buffer, w * h, + &vs->worker->tight.tight.offset); bytes =3D 3; } else { bytes =3D vs->client_pf.bytes_per_pixel; } =20 - bytes =3D tight_compress_data(vs, stream, w * h * bytes, - tight_conf[vs->tight->compression].raw_zlib_le= vel, + bytes =3D tight_compress_data(vs, stream, w * h * bytes, level, Z_DEFAULT_STRATEGY); =20 return (bytes >=3D 0); @@ -944,18 +946,19 @@ static int send_full_color_rect(VncState *vs, int x, = int y, int w, int h) =20 static int send_solid_rect(VncState *vs) { + VncTight *tight =3D &vs->worker->tight; size_t bytes; =20 vnc_write_u8(vs, VNC_TIGHT_FILL << 4); /* no flushing, no filter */ =20 - if (vs->tight->pixel24) { - tight_pack24(vs, vs->tight->tight.buffer, 1, &vs->tight->tight.off= set); + if (tight->pixel24) { + tight_pack24(vs, tight->tight.buffer, 1, &tight->tight.offset); bytes =3D 3; } else { bytes =3D vs->client_pf.bytes_per_pixel; } =20 - vnc_write(vs, vs->tight->tight.buffer, bytes); + vnc_write(vs, tight->tight.buffer, bytes); return 1; } =20 @@ -964,7 +967,7 @@ static int send_mono_rect(VncState *vs, int x, int y, { ssize_t bytes; int stream =3D 1; - int level =3D tight_conf[vs->tight->compression].mono_zlib_level; + int level =3D tight_conf[vs->worker->tight.compression].mono_zlib_leve= l; =20 #ifdef CONFIG_PNG if (tight_can_send_png_rect(vs, w, h)) { @@ -992,26 +995,26 @@ static int send_mono_rect(VncState *vs, int x, int y, uint32_t buf[2] =3D {bg, fg}; size_t ret =3D sizeof (buf); =20 - if (vs->tight->pixel24) { + if (vs->worker->tight.pixel24) { tight_pack24(vs, (unsigned char*)buf, 2, &ret); } vnc_write(vs, buf, ret); =20 - tight_encode_mono_rect32(vs->tight->tight.buffer, w, h, bg, fg); + tight_encode_mono_rect32(vs->worker->tight.tight.buffer, w, h, bg,= fg); break; } case 2: vnc_write(vs, &bg, 2); vnc_write(vs, &fg, 2); - tight_encode_mono_rect16(vs->tight->tight.buffer, w, h, bg, fg); + tight_encode_mono_rect16(vs->worker->tight.tight.buffer, w, h, bg,= fg); break; default: vnc_write_u8(vs, bg); vnc_write_u8(vs, fg); - tight_encode_mono_rect8(vs->tight->tight.buffer, w, h, bg, fg); + tight_encode_mono_rect8(vs->worker->tight.tight.buffer, w, h, bg, = fg); break; } - vs->tight->tight.offset =3D bytes; + vs->worker->tight.tight.offset =3D bytes; =20 bytes =3D tight_compress_data(vs, stream, bytes, level, Z_DEFAULT_STRA= TEGY); return (bytes >=3D 0); @@ -1040,8 +1043,9 @@ static void write_palette(int idx, uint32_t color, vo= id *opaque) =20 static bool send_gradient_rect(VncState *vs, int x, int y, int w, int h) { + VncTight *tight =3D &vs->worker->tight; int stream =3D 3; - int level =3D tight_conf[vs->tight->compression].gradient_zlib_level; + int level =3D tight_conf[tight->compression].gradient_zlib_level; ssize_t bytes; =20 if (vs->client_pf.bytes_per_pixel =3D=3D 1) { @@ -1051,23 +1055,23 @@ static bool send_gradient_rect(VncState *vs, int x,= int y, int w, int h) vnc_write_u8(vs, (stream | VNC_TIGHT_EXPLICIT_FILTER) << 4); vnc_write_u8(vs, VNC_TIGHT_FILTER_GRADIENT); =20 - buffer_reserve(&vs->tight->gradient, w * 3 * sizeof(int)); + buffer_reserve(&tight->gradient, w * 3 * sizeof(int)); =20 - if (vs->tight->pixel24) { - tight_filter_gradient24(vs, vs->tight->tight.buffer, w, h); + if (tight->pixel24) { + tight_filter_gradient24(vs, tight->tight.buffer, w, h); bytes =3D 3; } else if (vs->client_pf.bytes_per_pixel =3D=3D 4) { - tight_filter_gradient32(vs, (uint32_t *)vs->tight->tight.buffer, w= , h); + tight_filter_gradient32(vs, (uint32_t *)tight->tight.buffer, w, h); bytes =3D 4; } else { - tight_filter_gradient16(vs, (uint16_t *)vs->tight->tight.buffer, w= , h); + tight_filter_gradient16(vs, (uint16_t *)tight->tight.buffer, w, h); bytes =3D 2; } =20 - buffer_reset(&vs->tight->gradient); + buffer_reset(&tight->gradient); =20 bytes =3D w * h * bytes; - vs->tight->tight.offset =3D bytes; + tight->tight.offset =3D bytes; =20 bytes =3D tight_compress_data(vs, stream, bytes, level, Z_FILTERED); @@ -1077,8 +1081,9 @@ static bool send_gradient_rect(VncState *vs, int x, i= nt y, int w, int h) static int send_palette_rect(VncState *vs, int x, int y, int w, int h, VncPalette *palette) { + VncTight *tight =3D &vs->worker->tight; int stream =3D 2; - int level =3D tight_conf[vs->tight->compression].idx_zlib_level; + int level =3D tight_conf[tight->compression].idx_zlib_level; int colors; ssize_t bytes; =20 @@ -1105,12 +1110,12 @@ static int send_palette_rect(VncState *vs, int x, i= nt y, palette_iter(palette, write_palette, &priv); vnc_write(vs, header, palette_sz * sizeof(uint32_t)); =20 - if (vs->tight->pixel24) { + if (tight->pixel24) { tight_pack24(vs, vs->output.buffer + old_offset, colors, &offs= et); vs->output.offset =3D old_offset + offset; } =20 - tight_encode_indexed_rect32(vs->tight->tight.buffer, w * h, palett= e); + tight_encode_indexed_rect32(tight->tight.buffer, w * h, palette); break; } case 2: @@ -1121,14 +1126,14 @@ static int send_palette_rect(VncState *vs, int x, i= nt y, =20 palette_iter(palette, write_palette, &priv); vnc_write(vs, header, palette_sz * sizeof(uint16_t)); - tight_encode_indexed_rect16(vs->tight->tight.buffer, w * h, palett= e); + tight_encode_indexed_rect16(tight->tight.buffer, w * h, palette); break; } default: return -1; /* No palette for 8bits colors */ } bytes =3D w * h; - vs->tight->tight.offset =3D bytes; + tight->tight.offset =3D bytes; =20 bytes =3D tight_compress_data(vs, stream, bytes, level, Z_DEFAULT_STRATEGY); @@ -1147,7 +1152,7 @@ static int send_palette_rect(VncState *vs, int x, int= y, static void jpeg_init_destination(j_compress_ptr cinfo) { VncState *vs =3D cinfo->client_data; - Buffer *buffer =3D &vs->tight->jpeg; + Buffer *buffer =3D &vs->worker->tight.jpeg; =20 cinfo->dest->next_output_byte =3D (JOCTET *)buffer->buffer + buffer->o= ffset; cinfo->dest->free_in_buffer =3D (size_t)(buffer->capacity - buffer->of= fset); @@ -1157,7 +1162,7 @@ static void jpeg_init_destination(j_compress_ptr cinf= o) static boolean jpeg_empty_output_buffer(j_compress_ptr cinfo) { VncState *vs =3D cinfo->client_data; - Buffer *buffer =3D &vs->tight->jpeg; + Buffer *buffer =3D &vs->worker->tight.jpeg; =20 buffer->offset =3D buffer->capacity; buffer_reserve(buffer, 2048); @@ -1169,7 +1174,7 @@ static boolean jpeg_empty_output_buffer(j_compress_pt= r cinfo) static void jpeg_term_destination(j_compress_ptr cinfo) { VncState *vs =3D cinfo->client_data; - Buffer *buffer =3D &vs->tight->jpeg; + Buffer *buffer =3D &vs->worker->tight.jpeg; =20 buffer->offset =3D buffer->capacity - cinfo->dest->free_in_buffer; } @@ -1188,7 +1193,7 @@ static int send_jpeg_rect(VncState *vs, int x, int y,= int w, int h, int quality) return send_full_color_rect(vs, x, y, w, h); } =20 - buffer_reserve(&vs->tight->jpeg, 2048); + buffer_reserve(&vs->worker->tight.jpeg, 2048); =20 cinfo.err =3D jpeg_std_error(&jerr); jpeg_create_compress(&cinfo); @@ -1223,9 +1228,9 @@ static int send_jpeg_rect(VncState *vs, int x, int y,= int w, int h, int quality) =20 vnc_write_u8(vs, VNC_TIGHT_JPEG << 4); =20 - tight_send_compact_size(vs, vs->tight->jpeg.offset); - vnc_write(vs, vs->tight->jpeg.buffer, vs->tight->jpeg.offset); - buffer_reset(&vs->tight->jpeg); + tight_send_compact_size(vs, vs->worker->tight.jpeg.offset); + vnc_write(vs, vs->worker->tight.jpeg.buffer, vs->worker->tight.jpeg.of= fset); + buffer_reset(&vs->worker->tight.jpeg); =20 return 1; } @@ -1241,7 +1246,7 @@ static void write_png_palette(int idx, uint32_t pix, = void *opaque) VncState *vs =3D priv->vs; png_colorp color =3D &priv->png_palette[idx]; =20 - if (vs->tight->pixel24) + if (vs->worker->tight.pixel24) { color->red =3D (pix >> vs->client_pf.rshift) & vs->client_pf.rmax; color->green =3D (pix >> vs->client_pf.gshift) & vs->client_pf.gma= x; @@ -1266,12 +1271,12 @@ static void write_png_palette(int idx, uint32_t pix= , void *opaque) static void png_write_data(png_structp png_ptr, png_bytep data, png_size_t length) { - VncState *vs =3D png_get_io_ptr(png_ptr); + VncWorker *worker =3D png_get_io_ptr(png_ptr); =20 - buffer_reserve(&vs->tight->png, vs->tight->png.offset + length); - memcpy(vs->tight->png.buffer + vs->tight->png.offset, data, length); + buffer_reserve(&worker->tight.png, worker->tight.png.offset + length); + memcpy(worker->tight.png.buffer + worker->tight.png.offset, data, leng= th); =20 - vs->tight->png.offset +=3D length; + worker->tight.png.offset +=3D length; } =20 static void png_flush_data(png_structp png_ptr) @@ -1296,8 +1301,8 @@ static int send_png_rect(VncState *vs, int x, int y, = int w, int h, png_infop info_ptr; png_colorp png_palette =3D NULL; pixman_image_t *linebuf; - int level =3D tight_png_conf[vs->tight->compression].png_zlib_level; - int filters =3D tight_png_conf[vs->tight->compression].png_filters; + int level =3D tight_png_conf[vs->worker->tight.compression].png_zlib_l= evel; + int filters =3D tight_png_conf[vs->worker->tight.compression].png_filt= ers; uint8_t *buf; int dy; =20 @@ -1314,7 +1319,7 @@ static int send_png_rect(VncState *vs, int x, int y, = int w, int h, return -1; } =20 - png_set_write_fn(png_ptr, (void *) vs, png_write_data, png_flush_data); + png_set_write_fn(png_ptr, vs->worker, png_write_data, png_flush_data); png_set_compression_level(png_ptr, level); png_set_filter(png_ptr, PNG_FILTER_TYPE_DEFAULT, filters); =20 @@ -1341,23 +1346,23 @@ static int send_png_rect(VncState *vs, int x, int y= , int w, int h, png_set_PLTE(png_ptr, info_ptr, png_palette, palette_size(palette)= ); =20 if (vs->client_pf.bytes_per_pixel =3D=3D 4) { - tight_encode_indexed_rect32(vs->tight->tight.buffer, w * h, + tight_encode_indexed_rect32(vs->worker->tight.tight.buffer, w = * h, palette); } else { - tight_encode_indexed_rect16(vs->tight->tight.buffer, w * h, + tight_encode_indexed_rect16(vs->worker->tight.tight.buffer, w = * h, palette); } } =20 png_write_info(png_ptr, info_ptr); =20 - buffer_reserve(&vs->tight->png, 2048); + buffer_reserve(&vs->worker->tight.png, 2048); linebuf =3D qemu_pixman_linebuf_create(PIXMAN_BE_r8g8b8, w); buf =3D (uint8_t *)pixman_image_get_data(linebuf); for (dy =3D 0; dy < h; dy++) { if (color_type =3D=3D PNG_COLOR_TYPE_PALETTE) { - memcpy(buf, vs->tight->tight.buffer + (dy * w), w); + memcpy(buf, vs->worker->tight.tight.buffer + (dy * w), w); } else { qemu_pixman_linebuf_fill(linebuf, vs->vd->server, w, x, y + dy= ); } @@ -1375,27 +1380,27 @@ static int send_png_rect(VncState *vs, int x, int y= , int w, int h, =20 vnc_write_u8(vs, VNC_TIGHT_PNG << 4); =20 - tight_send_compact_size(vs, vs->tight->png.offset); - vnc_write(vs, vs->tight->png.buffer, vs->tight->png.offset); - buffer_reset(&vs->tight->png); + tight_send_compact_size(vs, vs->worker->tight.png.offset); + vnc_write(vs, vs->worker->tight.png.buffer, vs->worker->tight.png.offs= et); + buffer_reset(&vs->worker->tight.png); return 1; } #endif /* CONFIG_PNG */ =20 static void vnc_tight_start(VncState *vs) { - buffer_reset(&vs->tight->tight); + buffer_reset(&vs->worker->tight.tight); =20 // make the output buffer be the zlib buffer, so we can compress it la= ter - vs->tight->tmp =3D vs->output; - vs->output =3D vs->tight->tight; + vs->worker->tight.tmp =3D vs->output; + vs->output =3D vs->worker->tight.tight; } =20 static void vnc_tight_stop(VncState *vs) { // switch back to normal output/zlib buffers - vs->tight->tight =3D vs->output; - vs->output =3D vs->tight->tmp; + vs->worker->tight.tight =3D vs->output; + vs->output =3D vs->worker->tight.tmp; } =20 static int send_sub_rect_nojpeg(VncState *vs, int x, int y, int w, int h, @@ -1429,9 +1434,9 @@ static int send_sub_rect_jpeg(VncState *vs, int x, in= t y, int w, int h, int ret; =20 if (colors =3D=3D 0) { - if (force || (tight_jpeg_conf[vs->tight->quality].jpeg_full && + if (force || (tight_jpeg_conf[vs->worker->tight.quality].jpeg_full= && tight_detect_smooth_image(vs, w, h))) { - int quality =3D tight_conf[vs->tight->quality].jpeg_quality; + int quality =3D tight_conf[vs->worker->tight.quality].jpeg_qua= lity; =20 ret =3D send_jpeg_rect(vs, x, y, w, h, quality); } else { @@ -1443,9 +1448,9 @@ static int send_sub_rect_jpeg(VncState *vs, int x, in= t y, int w, int h, ret =3D send_mono_rect(vs, x, y, w, h, bg, fg); } else if (colors <=3D 256) { if (force || (colors > 96 && - tight_jpeg_conf[vs->tight->quality].jpeg_idx && + tight_jpeg_conf[vs->worker->tight.quality].jpeg_idx = && tight_detect_smooth_image(vs, w, h))) { - int quality =3D tight_conf[vs->tight->quality].jpeg_quality; + int quality =3D tight_conf[vs->worker->tight.quality].jpeg_qua= lity; =20 ret =3D send_jpeg_rect(vs, x, y, w, h, quality); } else { @@ -1469,6 +1474,7 @@ static void vnc_tight_cleanup(Notifier *n, void *valu= e) =20 static int send_sub_rect(VncState *vs, int x, int y, int w, int h) { + VncTight *tight =3D &vs->worker->tight; uint32_t bg =3D 0, fg =3D 0; int colors; int ret =3D 0; @@ -1483,20 +1489,20 @@ static int send_sub_rect(VncState *vs, int x, int y= , int w, int h) qemu_thread_atexit_add(&vnc_tight_cleanup_notifier); } =20 - vnc_framebuffer_update(vs, x, y, w, h, vs->tight->type); + vnc_framebuffer_update(vs, x, y, w, h, tight->type); =20 vnc_tight_start(vs); vnc_raw_send_framebuffer_update(vs, x, y, w, h); vnc_tight_stop(vs); =20 #ifdef CONFIG_VNC_JPEG - if (!vs->vd->non_adaptive && vs->tight->quality !=3D (uint8_t)-1) { + if (!vs->vd->non_adaptive && tight->quality !=3D (uint8_t)-1) { double freq =3D vnc_update_freq(vs, x, y, w, h); =20 - if (freq < tight_jpeg_conf[vs->tight->quality].jpeg_freq_min) { + if (freq < tight_jpeg_conf[tight->quality].jpeg_freq_min) { allow_jpeg =3D false; } - if (freq >=3D tight_jpeg_conf[vs->tight->quality].jpeg_freq_thresh= old) { + if (freq >=3D tight_jpeg_conf[tight->quality].jpeg_freq_threshold)= { force_jpeg =3D true; vnc_sent_lossy_rect(vs, x, y, w, h); } @@ -1506,7 +1512,7 @@ static int send_sub_rect(VncState *vs, int x, int y, = int w, int h) colors =3D tight_fill_palette(vs, x, y, w * h, &bg, &fg, color_count_p= alette); =20 #ifdef CONFIG_VNC_JPEG - if (allow_jpeg && vs->tight->quality !=3D (uint8_t)-1) { + if (allow_jpeg && tight->quality !=3D (uint8_t)-1) { ret =3D send_sub_rect_jpeg(vs, x, y, w, h, bg, fg, colors, color_count_palette, force_jpeg); } else { @@ -1523,7 +1529,7 @@ static int send_sub_rect(VncState *vs, int x, int y, = int w, int h) =20 static int send_sub_rect_solid(VncState *vs, int x, int y, int w, int h) { - vnc_framebuffer_update(vs, x, y, w, h, vs->tight->type); + vnc_framebuffer_update(vs, x, y, w, h, vs->worker->tight.type); =20 vnc_tight_start(vs); vnc_raw_send_framebuffer_update(vs, x, y, w, h); @@ -1541,8 +1547,8 @@ static int send_rect_simple(VncState *vs, int x, int = y, int w, int h, int rw, rh; int n =3D 0; =20 - max_size =3D tight_conf[vs->tight->compression].max_rect_size; - max_width =3D tight_conf[vs->tight->compression].max_rect_width; + max_size =3D tight_conf[vs->worker->tight.compression].max_rect_size; + max_width =3D tight_conf[vs->worker->tight.compression].max_rect_width; =20 if (split && (w > max_width || w * h > max_size)) { max_sub_width =3D (w > max_width) ? max_width : w; @@ -1647,20 +1653,21 @@ static int find_large_solid_color_rect(VncState *vs= , int x, int y, static int tight_send_framebuffer_update(VncState *vs, int x, int y, int w, int h) { + VncTight *tight =3D &vs->worker->tight; int max_rows; =20 if (vs->client_pf.bytes_per_pixel =3D=3D 4 && vs->client_pf.rmax =3D= =3D 0xFF && vs->client_pf.bmax =3D=3D 0xFF && vs->client_pf.gmax =3D=3D 0xFF) { - vs->tight->pixel24 =3D true; + tight->pixel24 =3D true; } else { - vs->tight->pixel24 =3D false; + tight->pixel24 =3D false; } =20 #ifdef CONFIG_VNC_JPEG - if (vs->tight->quality !=3D (uint8_t)-1) { + if (tight->quality !=3D (uint8_t)-1) { double freq =3D vnc_update_freq(vs, x, y, w, h); =20 - if (freq > tight_jpeg_conf[vs->tight->quality].jpeg_freq_threshold= ) { + if (freq > tight_jpeg_conf[tight->quality].jpeg_freq_threshold) { return send_rect_simple(vs, x, y, w, h, false); } } @@ -1672,8 +1679,8 @@ static int tight_send_framebuffer_update(VncState *vs= , int x, int y, =20 /* Calculate maximum number of rows in one non-solid rectangle. */ =20 - max_rows =3D tight_conf[vs->tight->compression].max_rect_size; - max_rows /=3D MIN(tight_conf[vs->tight->compression].max_rect_width, w= ); + max_rows =3D tight_conf[tight->compression].max_rect_size; + max_rows /=3D MIN(tight_conf[tight->compression].max_rect_width, w); =20 return find_large_solid_color_rect(vs, x, y, w, h, max_rows); } @@ -1681,33 +1688,33 @@ static int tight_send_framebuffer_update(VncState *= vs, int x, int y, int vnc_tight_send_framebuffer_update(VncState *vs, int x, int y, int w, int h) { - vs->tight->type =3D VNC_ENCODING_TIGHT; + vs->worker->tight.type =3D VNC_ENCODING_TIGHT; return tight_send_framebuffer_update(vs, x, y, w, h); } =20 int vnc_tight_png_send_framebuffer_update(VncState *vs, int x, int y, int w, int h) { - vs->tight->type =3D VNC_ENCODING_TIGHT_PNG; + vs->worker->tight.type =3D VNC_ENCODING_TIGHT_PNG; return tight_send_framebuffer_update(vs, x, y, w, h); } =20 void vnc_tight_clear(VncState *vs) { int i; - for (i =3D 0; i < ARRAY_SIZE(vs->tight->stream); i++) { - if (vs->tight->stream[i].opaque) { - deflateEnd(&vs->tight->stream[i]); + for (i =3D 0; i < ARRAY_SIZE(vs->worker->tight.stream); i++) { + if (vs->worker->tight.stream[i].opaque) { + deflateEnd(&vs->worker->tight.stream[i]); } } =20 - buffer_free(&vs->tight->tight); - buffer_free(&vs->tight->zlib); - buffer_free(&vs->tight->gradient); + buffer_free(&vs->worker->tight.tight); + buffer_free(&vs->worker->tight.zlib); + buffer_free(&vs->worker->tight.gradient); #ifdef CONFIG_VNC_JPEG - buffer_free(&vs->tight->jpeg); + buffer_free(&vs->worker->tight.jpeg); #endif #ifdef CONFIG_PNG - buffer_free(&vs->tight->png); + buffer_free(&vs->worker->tight.png); #endif } diff --git a/ui/vnc-enc-zlib.c b/ui/vnc-enc-zlib.c index 900ae5b30f6b..605030730a44 100644 --- a/ui/vnc-enc-zlib.c +++ b/ui/vnc-enc-zlib.c @@ -76,7 +76,7 @@ static int vnc_zlib_stop(VncState *vs) zstream->zalloc =3D vnc_zlib_zalloc; zstream->zfree =3D vnc_zlib_zfree; =20 - err =3D deflateInit2(zstream, vs->tight->compression, Z_DEFLATED, + err =3D deflateInit2(zstream, vs->worker->tight.compression, Z_DEF= LATED, MAX_WBITS, MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY); =20 @@ -85,16 +85,16 @@ static int vnc_zlib_stop(VncState *vs) return -1; } =20 - vs->zlib.level =3D vs->tight->compression; + vs->zlib.level =3D vs->worker->tight.compression; zstream->opaque =3D vs; } =20 - if (vs->tight->compression !=3D vs->zlib.level) { - if (deflateParams(zstream, vs->tight->compression, + if (vs->worker->tight.compression !=3D vs->zlib.level) { + if (deflateParams(zstream, vs->worker->tight.compression, Z_DEFAULT_STRATEGY) !=3D Z_OK) { return -1; } - vs->zlib.level =3D vs->tight->compression; + vs->zlib.level =3D vs->worker->tight.compression; } =20 // reserve memory in output buffer diff --git a/ui/vnc-enc-zrle.c b/ui/vnc-enc-zrle.c index bd33b890639f..4ed3d17d17a0 100644 --- a/ui/vnc-enc-zrle.c +++ b/ui/vnc-enc-zrle.c @@ -37,18 +37,18 @@ static const int bits_per_packed_pixel[] =3D { =20 static void vnc_zrle_start(VncState *vs) { - buffer_reset(&vs->zrle->zrle); + buffer_reset(&vs->worker->zrle.zrle); =20 /* make the output buffer be the zlib buffer, so we can compress it la= ter */ - vs->zrle->tmp =3D vs->output; - vs->output =3D vs->zrle->zrle; + vs->worker->zrle.tmp =3D vs->output; + vs->output =3D vs->worker->zrle.zrle; } =20 static void vnc_zrle_stop(VncState *vs) { /* switch back to normal output/zlib buffers */ - vs->zrle->zrle =3D vs->output; - vs->output =3D vs->zrle->tmp; + vs->worker->zrle.zrle =3D vs->output; + vs->output =3D vs->worker->zrle.tmp; } =20 static void *zrle_convert_fb(VncState *vs, int x, int y, int w, int h, @@ -56,24 +56,25 @@ static void *zrle_convert_fb(VncState *vs, int x, int y= , int w, int h, { Buffer tmp; =20 - buffer_reset(&vs->zrle->fb); - buffer_reserve(&vs->zrle->fb, w * h * bpp + bpp); + buffer_reset(&vs->worker->zrle.fb); + buffer_reserve(&vs->worker->zrle.fb, w * h * bpp + bpp); =20 tmp =3D vs->output; - vs->output =3D vs->zrle->fb; + vs->output =3D vs->worker->zrle.fb; =20 vnc_raw_send_framebuffer_update(vs, x, y, w, h); =20 - vs->zrle->fb =3D vs->output; + vs->worker->zrle.fb =3D vs->output; vs->output =3D tmp; - return vs->zrle->fb.buffer; + return vs->worker->zrle.fb.buffer; } =20 static int zrle_compress_data(VncState *vs, int level) { - z_streamp zstream =3D &vs->zrle->stream; + VncZrle *zrle =3D &vs->worker->zrle; + z_streamp zstream =3D &zrle->stream; =20 - buffer_reset(&vs->zrle->zlib); + buffer_reset(&zrle->zlib); =20 if (zstream->opaque !=3D vs) { int err; @@ -93,13 +94,13 @@ static int zrle_compress_data(VncState *vs, int level) } =20 /* reserve memory in output buffer */ - buffer_reserve(&vs->zrle->zlib, vs->zrle->zrle.offset + 64); + buffer_reserve(&zrle->zlib, zrle->zrle.offset + 64); =20 /* set pointers */ - zstream->next_in =3D vs->zrle->zrle.buffer; - zstream->avail_in =3D vs->zrle->zrle.offset; - zstream->next_out =3D vs->zrle->zlib.buffer; - zstream->avail_out =3D vs->zrle->zlib.capacity; + zstream->next_in =3D zrle->zrle.buffer; + zstream->avail_in =3D zrle->zrle.offset; + zstream->next_out =3D zrle->zlib.buffer; + zstream->avail_out =3D zrle->zlib.capacity; zstream->data_type =3D Z_BINARY; =20 /* start encoding */ @@ -108,8 +109,8 @@ static int zrle_compress_data(VncState *vs, int level) return -1; } =20 - vs->zrle->zlib.offset =3D vs->zrle->zlib.capacity - zstream->avail_out; - return vs->zrle->zlib.offset; + zrle->zlib.offset =3D zrle->zlib.capacity - zstream->avail_out; + return zrle->zlib.offset; } =20 /* Try to work out whether to use RLE and/or a palette. We do this by @@ -259,14 +260,14 @@ static int zrle_send_framebuffer_update(VncState *vs,= int x, int y, size_t bytes; int zywrle_level; =20 - if (vs->zrle->type =3D=3D VNC_ENCODING_ZYWRLE) { - if (!vs->vd->lossy || vs->tight->quality =3D=3D (uint8_t)-1 - || vs->tight->quality =3D=3D 9) { + if (vs->worker->zrle.type =3D=3D VNC_ENCODING_ZYWRLE) { + if (!vs->vd->lossy || vs->worker->tight.quality =3D=3D (uint8_t)-1 + || vs->worker->tight.quality =3D=3D 9) { zywrle_level =3D 0; - vs->zrle->type =3D VNC_ENCODING_ZRLE; - } else if (vs->tight->quality < 3) { + vs->worker->zrle.type =3D VNC_ENCODING_ZRLE; + } else if (vs->worker->tight.quality < 3) { zywrle_level =3D 3; - } else if (vs->tight->quality < 6) { + } else if (vs->worker->tight.quality < 6) { zywrle_level =3D 2; } else { zywrle_level =3D 1; @@ -337,30 +338,30 @@ static int zrle_send_framebuffer_update(VncState *vs,= int x, int y, =20 vnc_zrle_stop(vs); bytes =3D zrle_compress_data(vs, Z_DEFAULT_COMPRESSION); - vnc_framebuffer_update(vs, x, y, w, h, vs->zrle->type); + vnc_framebuffer_update(vs, x, y, w, h, vs->worker->zrle.type); vnc_write_u32(vs, bytes); - vnc_write(vs, vs->zrle->zlib.buffer, vs->zrle->zlib.offset); + vnc_write(vs, vs->worker->zrle.zlib.buffer, vs->worker->zrle.zlib.offs= et); return 1; } =20 int vnc_zrle_send_framebuffer_update(VncState *vs, int x, int y, int w, in= t h) { - vs->zrle->type =3D VNC_ENCODING_ZRLE; + vs->worker->zrle.type =3D VNC_ENCODING_ZRLE; return zrle_send_framebuffer_update(vs, x, y, w, h); } =20 int vnc_zywrle_send_framebuffer_update(VncState *vs, int x, int y, int w, = int h) { - vs->zrle->type =3D VNC_ENCODING_ZYWRLE; + vs->worker->zrle.type =3D VNC_ENCODING_ZYWRLE; return zrle_send_framebuffer_update(vs, x, y, w, h); } =20 void vnc_zrle_clear(VncState *vs) { - if (vs->zrle->stream.opaque) { - deflateEnd(&vs->zrle->stream); + if (vs->worker->zrle.stream.opaque) { + deflateEnd(&vs->worker->zrle.stream); } - buffer_free(&vs->zrle->zrle); - buffer_free(&vs->zrle->fb); - buffer_free(&vs->zrle->zlib); + buffer_free(&vs->worker->zrle.zrle); + buffer_free(&vs->worker->zrle.fb); + buffer_free(&vs->worker->zrle.zlib); } diff --git a/ui/vnc-jobs.c b/ui/vnc-jobs.c index fcca7ec632b1..d019d88536b7 100644 --- a/ui/vnc-jobs.c +++ b/ui/vnc-jobs.c @@ -185,14 +185,12 @@ static void vnc_async_encoding_start(VncState *orig, = VncState *local) local->vnc_encoding =3D orig->vnc_encoding; local->features =3D orig->features; local->vd =3D orig->vd; - local->lossy_rect =3D orig->lossy_rect; + local->worker =3D orig->worker; local->write_pixels =3D orig->write_pixels; local->client_pf =3D orig->client_pf; local->client_be =3D orig->client_be; - local->tight =3D orig->tight; local->zlib =3D orig->zlib; local->hextile =3D orig->hextile; - local->zrle =3D orig->zrle; local->client_width =3D orig->client_width; local->client_height =3D orig->client_height; } @@ -200,11 +198,8 @@ static void vnc_async_encoding_start(VncState *orig, V= ncState *local) static void vnc_async_encoding_end(VncState *orig, VncState *local) { buffer_free(&local->output); - orig->tight =3D local->tight; orig->zlib =3D local->zlib; orig->hextile =3D local->hextile; - orig->zrle =3D local->zrle; - orig->lossy_rect =3D local->lossy_rect; } =20 static bool vnc_worker_clamp_rect(VncState *vs, VncJob *job, VncRect *rect) diff --git a/ui/vnc.c b/ui/vnc.c index 9e097dc4b46d..17fcf377d7f8 100644 --- a/ui/vnc.c +++ b/ui/vnc.c @@ -1306,8 +1306,6 @@ static void vnc_disconnect_start(VncState *vs) =20 void vnc_disconnect_finish(VncState *vs) { - int i; - trace_vnc_client_disconnect_finish(vs, vs->ioc); =20 vnc_jobs_join(vs); /* Wait encoding jobs */ @@ -1350,18 +1348,13 @@ void vnc_disconnect_finish(VncState *vs) } buffer_free(&vs->jobs_buffer); =20 - for (i =3D 0; i < VNC_STAT_ROWS; ++i) { - g_free(vs->lossy_rect[i]); - } - g_free(vs->lossy_rect); + g_free(vs->worker); =20 object_unref(OBJECT(vs->ioc)); vs->ioc =3D NULL; object_unref(OBJECT(vs->sioc)); vs->sioc =3D NULL; vs->magic =3D 0; - g_free(vs->zrle); - g_free(vs->tight); g_free(vs); } =20 @@ -2131,8 +2124,8 @@ static void set_encodings(VncState *vs, int32_t *enco= dings, size_t n_encodings) =20 vs->features =3D 0; vs->vnc_encoding =3D 0; - vs->tight->compression =3D 9; - vs->tight->quality =3D -1; /* Lossless by default */ + vs->worker->tight.compression =3D 9; + vs->worker->tight.quality =3D -1; /* Lossless by default */ vs->absolute =3D -1; =20 /* @@ -2220,11 +2213,11 @@ static void set_encodings(VncState *vs, int32_t *en= codings, size_t n_encodings) vnc_server_cut_text_caps(vs); break; case VNC_ENCODING_COMPRESSLEVEL0 ... VNC_ENCODING_COMPRESSLEVEL0 += 9: - vs->tight->compression =3D (enc & 0x0F); + vs->worker->tight.compression =3D (enc & 0x0F); break; case VNC_ENCODING_QUALITYLEVEL0 ... VNC_ENCODING_QUALITYLEVEL0 + 9: if (vs->vd->lossy) { - vs->tight->quality =3D (enc & 0x0F); + vs->worker->tight.quality =3D (enc & 0x0F); } break; default: @@ -2963,7 +2956,7 @@ void vnc_sent_lossy_rect(VncState *vs, int x, int y, = int w, int h) =20 for (j =3D y; j <=3D h; j++) { for (i =3D x; i <=3D w; i++) { - vs->lossy_rect[j][i] =3D 1; + vs->worker->lossy_rect[j][i] =3D 1; } } } @@ -2986,11 +2979,11 @@ static int vnc_refresh_lossy_rect(VncDisplay *vd, i= nt x, int y) continue; } =20 - if (!vs->lossy_rect[sty][stx]) { + if (!vs->worker->lossy_rect[sty][stx]) { continue; } =20 - vs->lossy_rect[sty][stx] =3D 0; + vs->worker->lossy_rect[sty][stx] =3D 0; for (j =3D 0; j < VNC_STAT_RECT; ++j) { bitmap_set(vs->dirty[y + j], x / VNC_DIRTY_PIXELS_PER_BIT, @@ -3242,11 +3235,9 @@ static void vnc_connect(VncDisplay *vd, QIOChannelSo= cket *sioc, { VncState *vs =3D g_new0(VncState, 1); bool first_client =3D QTAILQ_EMPTY(&vd->clients); - int i; =20 trace_vnc_client_connect(vs, sioc); - vs->zrle =3D g_new0(VncZrle, 1); - vs->tight =3D g_new0(VncTight, 1); + vs->worker =3D g_new0(VncWorker, 1); vs->magic =3D VNC_MAGIC; vs->sioc =3D sioc; object_ref(OBJECT(vs->sioc)); @@ -3254,23 +3245,23 @@ static void vnc_connect(VncDisplay *vd, QIOChannelS= ocket *sioc, object_ref(OBJECT(vs->ioc)); vs->vd =3D vd; =20 - 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); =20 - 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(&vs->worker->tight.tight, "vnc-tight/%p", sioc); + buffer_init(&vs->worker->tight.zlib, "vnc-tight-zlib/%p", sioc); + buffer_init(&vs->worker->tight.gradient, "vnc-tight-gradient/%p", sioc= ); #ifdef CONFIG_VNC_JPEG - buffer_init(&vs->tight->jpeg, "vnc-tight-jpeg/%p", sioc); + buffer_init(&vs->worker->tight.jpeg, "vnc-tight-jpeg/%p", sioc); #endif #ifdef CONFIG_PNG - buffer_init(&vs->tight->png, "vnc-tight-png/%p", sioc); + buffer_init(&vs->worker->tight.png, "vnc-tight-png/%p", sioc); #endif - buffer_init(&vs->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(&vs->zlib.zlib, "vnc-zlib/%p", sioc); + buffer_init(&vs->worker->zrle.zrle, "vnc-zrle/%p", sioc); + buffer_init(&vs->worker->zrle.fb, "vnc-zrle-fb/%p", sioc); + buffer_init(&vs->worker->zrle.zlib, "vnc-zrle-zlib/%p", sioc); =20 if (skipauth) { vs->auth =3D VNC_AUTH_NONE; @@ -3287,11 +3278,6 @@ static void vnc_connect(VncDisplay *vd, QIOChannelSo= cket *sioc, VNC_DEBUG("Client sioc=3D%p ws=3D%d auth=3D%d subauth=3D%d\n", sioc, websocket, vs->auth, vs->subauth); =20 - vs->lossy_rect =3D g_malloc0(VNC_STAT_ROWS * sizeof (*vs->lossy_rect)); - for (i =3D 0; i < VNC_STAT_ROWS; ++i) { - vs->lossy_rect[i] =3D 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); diff --git a/ui/vnc-enc-zrle.c.inc b/ui/vnc-enc-zrle.c.inc index 2ef7501d5216..964beef74bdd 100644 --- a/ui/vnc-enc-zrle.c.inc +++ b/ui/vnc-enc-zrle.c.inc @@ -96,7 +96,7 @@ static void ZRLE_ENCODE(VncState *vs, int x, int y, int w= , int h, static void ZRLE_ENCODE_TILE(VncState *vs, ZRLE_PIXEL *data, int w, int h, int zywrle_level) { - VncPalette *palette =3D &vs->zrle->palette; + VncPalette *palette =3D &vs->worker->zrle.palette; =20 int runs =3D 0; int single_pixels =3D 0; --=20 2.49.0 From nobody Sat Nov 15 18:49:36 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=reject dis=none) header.from=rsg.ci.i.u-tokyo.ac.jp Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1748701320199322.54227874082676; Sat, 31 May 2025 07:22:00 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1uLN5K-0002kx-8B; Sat, 31 May 2025 10:21:18 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uLN5G-0002kD-C2 for qemu-devel@nongnu.org; Sat, 31 May 2025 10:21:15 -0400 Received: from www3579.sakura.ne.jp ([49.212.243.89]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uLN5D-0007nM-Bj for qemu-devel@nongnu.org; Sat, 31 May 2025 10:21:14 -0400 Received: from [192.168.10.111] (p865013-ipoe.ipoe.ocn.ne.jp [153.242.222.12]) (authenticated bits=0) by www3579.sakura.ne.jp (8.16.1/8.16.1) with ESMTPSA id 54VEKrPa069146 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO); Sat, 31 May 2025 23:20:59 +0900 (JST) (envelope-from odaki@rsg.ci.i.u-tokyo.ac.jp) DKIM-Signature: a=rsa-sha256; bh=0TzJO7aszXohfGSpFv6MxysdZXOeS4wdCSQFZAFq2lQ=; c=relaxed/relaxed; d=rsg.ci.i.u-tokyo.ac.jp; h=From:Date:Subject:Message-Id:To; s=rs20250326; t=1748701259; v=1; b=Csh1visLiz9H3y8aldDZuQvfugmyShs906h96UGZGV3WTbxkNMD88UOFnxlLWZim BoZ8MiIuwbeR5OT+j8V/kQdBztWpy0qx//9C3A2V+ODZhG23wem1hI6VMDg264Bo a3vXTKnDNvbJiJ0ppZgB1WcR7oZ8Tr0n7d/UEAPCjR+I6p0CbxfZRxTOOOdkLQOa N5IFWDulrbFwVHxHJBA5s3S9fs9Mu8BgbcwRrYvZWF4jfTBFv533rNTqxJ13eii+ E0+KL8TahXLUDbpoFkwkKzKC7bAYChWt6QIhJMuSgR6xY9HbAWbWuVQgEFquAwSX x3tgy+Ha3vZ0zdlwkUJrGA== From: Akihiko Odaki Date: Sat, 31 May 2025 23:20:42 +0900 Subject: [PATCH v2 2/2] ui/vnc: Do not copy z_stream MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250531-zlib-v2-2-b75c4b4769e1@rsg.ci.i.u-tokyo.ac.jp> References: <20250531-zlib-v2-0-b75c4b4769e1@rsg.ci.i.u-tokyo.ac.jp> In-Reply-To: <20250531-zlib-v2-0-b75c4b4769e1@rsg.ci.i.u-tokyo.ac.jp> To: qemu-devel@nongnu.org Cc: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , devel@daynix.com, Akihiko Odaki , =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= X-Mailer: b4 0.15-dev-edae6 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=49.212.243.89; envelope-from=odaki@rsg.ci.i.u-tokyo.ac.jp; helo=www3579.sakura.ne.jp X-Spam_score_int: -16 X-Spam_score: -1.7 X-Spam_bar: - X-Spam_report: (-1.7 / 5.0 requ) BAYES_00=-1.9, DKIM_INVALID=0.1, DKIM_SIGNED=0.1, RCVD_IN_VALIDITY_CERTIFIED_BLOCKED=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZM-MESSAGEID: 1748701323441116600 vnc_worker_thread_loop() copies z_stream stored in its local VncState to the persistent VncState, and the copied one is freed with deflateEnd() later. However, deflateEnd() refuses to operate with a copied z_stream and returns Z_STREAM_ERROR, leaking the allocated memory. Avoid copying the zlib state to fix the memory leak. Fixes: bd023f953e5e ("vnc: threaded VNC server") Signed-off-by: Akihiko Odaki Reviewed-by: Philippe Mathieu-Daud=C3=A9 --- ui/vnc.h | 2 +- ui/vnc-enc-zlib.c | 30 +++++++++++++++--------------- ui/vnc-jobs.c | 2 -- ui/vnc.c | 2 +- 4 files changed, 17 insertions(+), 19 deletions(-) diff --git a/ui/vnc.h b/ui/vnc.h index 1dc76c270c35..78a5fdfdc0d0 100644 --- a/ui/vnc.h +++ b/ui/vnc.h @@ -265,6 +265,7 @@ typedef struct VncWorker { uint8_t lossy_rect[VNC_STAT_ROWS][VNC_STAT_COLS]; =20 VncTight tight; + VncZlib zlib; VncZrle zrle; } VncWorker; =20 @@ -345,7 +346,6 @@ struct VncState /* Encoding specific, if you add something here, don't forget to * update vnc_async_encoding_start() */ - VncZlib zlib; VncHextile hextile; VncZywrle zywrle; =20 diff --git a/ui/vnc-enc-zlib.c b/ui/vnc-enc-zlib.c index 605030730a44..d8b4cf038b02 100644 --- a/ui/vnc-enc-zlib.c +++ b/ui/vnc-enc-zlib.c @@ -48,21 +48,21 @@ void vnc_zlib_zfree(void *x, void *addr) =20 static void vnc_zlib_start(VncState *vs) { - buffer_reset(&vs->zlib.zlib); + buffer_reset(&vs->worker->zlib.zlib); =20 // make the output buffer be the zlib buffer, so we can compress it la= ter - vs->zlib.tmp =3D vs->output; - vs->output =3D vs->zlib.zlib; + vs->worker->zlib.tmp =3D vs->output; + vs->output =3D vs->worker->zlib.zlib; } =20 static int vnc_zlib_stop(VncState *vs) { - z_streamp zstream =3D &vs->zlib.stream; + z_streamp zstream =3D &vs->worker->zlib.stream; int previous_out; =20 // switch back to normal output/zlib buffers - vs->zlib.zlib =3D vs->output; - vs->output =3D vs->zlib.tmp; + vs->worker->zlib.zlib =3D vs->output; + vs->output =3D vs->worker->zlib.tmp; =20 // compress the zlib buffer =20 @@ -85,24 +85,24 @@ static int vnc_zlib_stop(VncState *vs) return -1; } =20 - vs->zlib.level =3D vs->worker->tight.compression; + vs->worker->zlib.level =3D vs->worker->tight.compression; zstream->opaque =3D vs; } =20 - if (vs->worker->tight.compression !=3D vs->zlib.level) { + if (vs->worker->tight.compression !=3D vs->worker->zlib.level) { if (deflateParams(zstream, vs->worker->tight.compression, Z_DEFAULT_STRATEGY) !=3D Z_OK) { return -1; } - vs->zlib.level =3D vs->worker->tight.compression; + vs->worker->zlib.level =3D vs->worker->tight.compression; } =20 // reserve memory in output buffer - buffer_reserve(&vs->output, vs->zlib.zlib.offset + 64); + buffer_reserve(&vs->output, vs->worker->zlib.zlib.offset + 64); =20 // set pointers - zstream->next_in =3D vs->zlib.zlib.buffer; - zstream->avail_in =3D vs->zlib.zlib.offset; + zstream->next_in =3D vs->worker->zlib.zlib.buffer; + zstream->avail_in =3D vs->worker->zlib.zlib.offset; zstream->next_out =3D vs->output.buffer + vs->output.offset; zstream->avail_out =3D vs->output.capacity - vs->output.offset; previous_out =3D zstream->avail_out; @@ -147,8 +147,8 @@ int vnc_zlib_send_framebuffer_update(VncState *vs, int = x, int y, int w, int h) =20 void vnc_zlib_clear(VncState *vs) { - if (vs->zlib.stream.opaque) { - deflateEnd(&vs->zlib.stream); + if (vs->worker->zlib.stream.opaque) { + deflateEnd(&vs->worker->zlib.stream); } - buffer_free(&vs->zlib.zlib); + buffer_free(&vs->worker->zlib.zlib); } diff --git a/ui/vnc-jobs.c b/ui/vnc-jobs.c index d019d88536b7..dbbf62212c79 100644 --- a/ui/vnc-jobs.c +++ b/ui/vnc-jobs.c @@ -189,7 +189,6 @@ static void vnc_async_encoding_start(VncState *orig, Vn= cState *local) local->write_pixels =3D orig->write_pixels; local->client_pf =3D orig->client_pf; local->client_be =3D orig->client_be; - local->zlib =3D orig->zlib; local->hextile =3D orig->hextile; local->client_width =3D orig->client_width; local->client_height =3D orig->client_height; @@ -198,7 +197,6 @@ static void vnc_async_encoding_start(VncState *orig, Vn= cState *local) static void vnc_async_encoding_end(VncState *orig, VncState *local) { buffer_free(&local->output); - orig->zlib =3D local->zlib; orig->hextile =3D local->hextile; } =20 diff --git a/ui/vnc.c b/ui/vnc.c index 17fcf377d7f8..b55d80b9b003 100644 --- a/ui/vnc.c +++ b/ui/vnc.c @@ -3258,7 +3258,7 @@ static void vnc_connect(VncDisplay *vd, QIOChannelSoc= ket *sioc, #ifdef CONFIG_PNG buffer_init(&vs->worker->tight.png, "vnc-tight-png/%p", sioc); #endif - buffer_init(&vs->zlib.zlib, "vnc-zlib/%p", sioc); + buffer_init(&vs->worker->zlib.zlib, "vnc-zlib/%p", sioc); buffer_init(&vs->worker->zrle.zrle, "vnc-zrle/%p", sioc); buffer_init(&vs->worker->zrle.fb, "vnc-zrle-fb/%p", sioc); buffer_init(&vs->worker->zrle.zlib, "vnc-zrle-zlib/%p", sioc); --=20 2.49.0