diff --git a/usr.sbin/bhyve/Makefile b/usr.sbin/bhyve/Makefile --- a/usr.sbin/bhyve/Makefile +++ b/usr.sbin/bhyve/Makefile @@ -56,6 +56,7 @@ pci_xhci.c \ qemu_fwcfg.c \ qemu_loader.c \ + rendezvous.c \ smbiostbl.c \ sockstream.c \ tpm_device.c \ diff --git a/usr.sbin/bhyve/bhyverun.c b/usr.sbin/bhyve/bhyverun.c --- a/usr.sbin/bhyve/bhyverun.c +++ b/usr.sbin/bhyve/bhyverun.c @@ -110,6 +110,8 @@ static void vm_loop(struct vmctx *ctx, struct vcpu *vcpu); +void rendezvous(void); + static struct vcpu_info { struct vmctx *ctx; struct vcpu *vcpu; @@ -765,6 +767,11 @@ init_gdb(ctx); #endif + /* + * Ensure all components in bhyve is initialized before calling + * rendezvous + */ + rendezvous(); /* * Add all vCPUs. */ diff --git a/usr.sbin/bhyve/debug.h b/usr.sbin/bhyve/debug.h --- a/usr.sbin/bhyve/debug.h +++ b/usr.sbin/bhyve/debug.h @@ -28,6 +28,7 @@ #ifndef _DEBUG_H_ #define _DEBUG_H_ +#include extern int raw_stdio; diff --git a/usr.sbin/bhyve/debug.h b/usr.sbin/bhyve/rendezvous.h copy from usr.sbin/bhyve/debug.h copy to usr.sbin/bhyve/rendezvous.h --- a/usr.sbin/bhyve/debug.h +++ b/usr.sbin/bhyve/rendezvous.h @@ -1,7 +1,7 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * - * Copyright (c) 2019 Vincenzo Maffione + * Copyright (c) 2024 SHENGYI HONG * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -25,21 +25,18 @@ * SUCH DAMAGE. */ -#ifndef _DEBUG_H_ -#define _DEBUG_H_ +#ifndef _RENDEZVOUS_H_ +#define _RENDEZVOUS_H_ +#include +#include -extern int raw_stdio; - -#define FPRINTLN(filep, fmt, arg...) \ - do { \ - if (raw_stdio) \ - fprintf(filep, fmt "\r\n", ##arg); \ - else \ - fprintf(filep, fmt "\n", ##arg); \ - } while (0) - -#define PRINTLN(fmt, arg...) FPRINTLN(stdout, fmt, ##arg) -#define EPRINTLN(fmt, arg...) FPRINTLN(stderr, fmt, ##arg) +/* + * notify will send the member to main thread, the main thread will takes + * the responsibility to destory the resource of rendezvous. Thus the caller + * should consider the member is destroyed after using rendezvous_member_notify. + */ +void rendezvous_notify(void); +void rendezvous_add_member(void); -#endif +#endif /* _RENDEZVOUS_H_ */ diff --git a/usr.sbin/bhyve/rendezvous.c b/usr.sbin/bhyve/rendezvous.c new file mode 100644 --- /dev/null +++ b/usr.sbin/bhyve/rendezvous.c @@ -0,0 +1,119 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2024 SHENGYI HONG + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include + +#include "debug.h" +#include "rendezvous.h" + +/* + * The rendezvous layer provide a abstraction when components in bhyve like rfb + * and tcp socket needs to wait for connection, when more than two wait is + * specified, the original design will depends on the order of arguments passed + * to the bhyve itself. Currently, the gdb part does not join the rendezvous + * because GDB stop the vcpu when waiting for connection. + */ + +struct rendezvous_softc { + pthread_mutex_t + mtx; /* lock prevent race condition from member and wait thread */ + pthread_cond_t cond; /* cond variable to notify the wait thread */ + int counter; +}; + +typedef struct rendezvous_softc *rendezvous_softc_t; + +void rendezvous(void); + +static rendezvous_softc_t +get_rendezvous_softc(void) +{ + static rendezvous_softc_t softc = NULL; + int error; + + if (softc == NULL) { + softc = malloc(sizeof(struct rendezvous_softc)); + if ((error = pthread_mutex_init(&softc->mtx, NULL)) != 0) + errc(1, error, "init rendezvous mutex"); + if ((error = pthread_cond_init(&softc->cond, NULL)) != 0) + errc(1, error, "init rendezvous cond variable"); + softc->counter = 0; + } + + return (softc); +} + +void +rendezvous_add_member(void) +{ + rendezvous_softc_t softc = get_rendezvous_softc(); + + if (softc == NULL) + return; + + pthread_mutex_lock(&softc->mtx); + softc->counter += 1; + pthread_mutex_unlock(&softc->mtx); + + return; +} + +void +rendezvous_notify(void) +{ + rendezvous_softc_t softc = get_rendezvous_softc(); + + if (softc == NULL) + return; + + pthread_mutex_lock(&softc->mtx); + softc->counter--; + pthread_cond_signal(&softc->cond); + pthread_mutex_unlock(&softc->mtx); +} + +void +rendezvous(void) +{ + rendezvous_softc_t softc = get_rendezvous_softc(); + + if (softc->counter == 0) + return; + + while (true) { + pthread_mutex_lock(&softc->mtx); + pthread_cond_wait(&softc->cond, &softc->mtx); + if (softc->counter == 0) + break; + pthread_mutex_unlock(&softc->mtx); + } + + pthread_cond_destroy(&softc->cond); + pthread_mutex_destroy(&softc->mtx); +} diff --git a/usr.sbin/bhyve/rfb.c b/usr.sbin/bhyve/rfb.c --- a/usr.sbin/bhyve/rfb.c +++ b/usr.sbin/bhyve/rfb.c @@ -52,17 +52,17 @@ #include #include #include -#include #include +#include #include #include #include - #include #include "bhyvegc.h" -#include "debug.h" #include "console.h" +#include "debug.h" +#include "rendezvous.h" #include "rfb.h" #include "sockstream.h" @@ -140,9 +140,7 @@ atomic_bool input_detected; atomic_bool update_pixfmt; - pthread_mutex_t mtx; pthread_mutex_t pixfmt_mtx; - pthread_cond_t cond; int hw_crc; uint32_t *crc; /* WxH crc cells */ @@ -1225,9 +1223,7 @@ cfd = accept(rc->sfd, NULL, NULL); if (rc->conn_wait) { - pthread_mutex_lock(&rc->mtx); - pthread_cond_signal(&rc->cond); - pthread_mutex_unlock(&rc->mtx); + rendezvous_notify(); rc->conn_wait = 0; } rfb_handle(rc, cfd); @@ -1328,23 +1324,13 @@ rc->hw_crc = sse42_supported(); rc->conn_wait = wait; - if (wait) { - pthread_mutex_init(&rc->mtx, NULL); - pthread_cond_init(&rc->cond, NULL); - } + if (wait) + rendezvous_add_member(); pthread_mutex_init(&rc->pixfmt_mtx, NULL); pthread_create(&rc->tid, NULL, rfb_thr, rc); pthread_set_name_np(rc->tid, "rfb"); - if (wait) { - DPRINTF(("Waiting for rfb client...")); - pthread_mutex_lock(&rc->mtx); - pthread_cond_wait(&rc->cond, &rc->mtx); - pthread_mutex_unlock(&rc->mtx); - DPRINTF(("rfb client connected")); - } - freeaddrinfo(ai); return (0);