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 @@ -81,6 +81,7 @@ #include "mem.h" #include "mevent.h" #include "pci_emul.h" +#include "rendezvous.h" #ifdef __amd64__ #include "amd64/pci_lpc.h" #endif @@ -764,7 +765,7 @@ #ifdef BHYVE_GDB init_gdb(ctx); #endif - + 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,25 @@ * SUCH DAMAGE. */ -#ifndef _DEBUG_H_ -#define _DEBUG_H_ +#ifndef _RENDEZVOUS_H_ +#define _RENDEZVOUS_H_ +#include +#include -extern int raw_stdio; +struct rendezvous_member; -#define FPRINTLN(filep, fmt, arg...) \ - do { \ - if (raw_stdio) \ - fprintf(filep, fmt "\r\n", ##arg); \ - else \ - fprintf(filep, fmt "\n", ##arg); \ - } while (0) +typedef struct rendezvous_member *rendezvous_member_t; -#define PRINTLN(fmt, arg...) FPRINTLN(stdout, fmt, ##arg) -#define EPRINTLN(fmt, arg...) FPRINTLN(stderr, fmt, ##arg) +rendezvous_member_t rendezvous_member_create(const char *name); -#endif +/* + * 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_member_notify(rendezvous_member_t member); +bool rendezvous_add_member(rendezvous_member_t member); +void rendezvous(void); + +#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,115 @@ +/*- + * 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 wait force connection. + */ + +/* + * not so much components in the bhyve userspace needs to wait, + * set to 10 so that we can modify it to be capable to wait more + * components + */ +#define MEMBERS_LIMIT 10 + +typedef struct rendezvous_member { + pthread_mutex_t + mtx; /* lock prevent race condition from member and wait thread */ + pthread_cond_t cond; /* cond variable to notify the wait thread */ + const char *name; +} rendezvous_member; + +static rendezvous_member_t members[MEMBERS_LIMIT]; +static int total_members = 0; + +rendezvous_member_t +rendezvous_member_create(const char *name) +{ + int error; + rendezvous_member_t member = malloc(sizeof(rendezvous_member)); + + if ((error = pthread_mutex_init(&member->mtx, NULL)) != 0) { + errc(1, error, "rendezvous mutex %s init", name); + goto error; + } + + if ((error = pthread_cond_init(&member->cond, NULL)) != 0) { + errc(1, error, "rendezvous cond %s init", name); + goto error; + } + + member->name = name; + return (member); +error: + free(member); + return (NULL); +} + +void +rendezvous_member_notify(rendezvous_member_t member) +{ + pthread_mutex_lock(&member->mtx); + pthread_cond_signal(&member->cond); + pthread_mutex_unlock(&member->mtx); +} + +bool +rendezvous_add_member(rendezvous_member_t member) +{ + if (total_members + 1 > MEMBERS_LIMIT) + return (false); + + members[total_members++] = member; + return (true); +} + +void +rendezvous(void) +{ + int i = 0; + + for (i = 0; i < total_members; i++) { + pthread_mutex_lock(&members[i]->mtx); + pthread_cond_wait(&members[i]->cond, &members[i]->mtx); + pthread_mutex_unlock(&members[i]->mtx); + pthread_cond_destroy(&members[i]->cond); + pthread_mutex_destroy(&members[i]->mtx); + PRINTLN("%s in here!", members[i]->name); + free(members[i]); + } +} 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,8 @@ atomic_bool input_detected; atomic_bool update_pixfmt; - pthread_mutex_t mtx; pthread_mutex_t pixfmt_mtx; - pthread_cond_t cond; + rendezvous_member_t rendezvous; int hw_crc; uint32_t *crc; /* WxH crc cells */ @@ -1225,9 +1224,8 @@ 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_member_notify(rc->rendezvous); + rc->rendezvous = NULL; rc->conn_wait = 0; } rfb_handle(rc, cfd); @@ -1329,21 +1327,16 @@ rc->conn_wait = wait; if (wait) { - pthread_mutex_init(&rc->mtx, NULL); - pthread_cond_init(&rc->cond, NULL); + rc->rendezvous = rendezvous_member_create("rfb"); + rendezvous_add_member(rc->rendezvous); } pthread_mutex_init(&rc->pixfmt_mtx, NULL); pthread_create(&rc->tid, NULL, rfb_thr, rc); pthread_set_name_np(rc->tid, "rfb"); - if (wait) { + 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);