+ return thread_run_test(NULL, MAXIMUM_THREADS, &test_multi_load_worker, 0,
+ NULL) && res;
+}
+
+static void test_obj_create_one(void)
+{
+ char tids[12], oid[40], sn[30], ln[30];
+ int id = get_new_uid();
+
+ BIO_snprintf(tids, sizeof(tids), "%d", id);
+ BIO_snprintf(oid, sizeof(oid), "1.3.6.1.4.1.16604.%s", tids);
+ BIO_snprintf(sn, sizeof(sn), "short-name-%s", tids);
+ BIO_snprintf(ln, sizeof(ln), "long-name-%s", tids);
+ if (!TEST_int_ne(id, 0)
+ || !TEST_true(id = OBJ_create(oid, sn, ln))
+ || !TEST_true(OBJ_add_sigid(id, NID_sha3_256, NID_rsa)))
+ multi_set_success(0);
+}
+
+static int test_obj_add(void)
+{
+ return thread_run_test(&test_obj_create_one,
+ MAXIMUM_THREADS, &test_obj_create_one,
+ 1, default_provider);
+}
+
+#if !defined(OPENSSL_NO_DGRAM) && !defined(OPENSSL_NO_SOCK)
+static BIO *multi_bio1, *multi_bio2;
+
+static void test_bio_dgram_pair_worker(void)
+{
+ ossl_unused int r;
+ int ok = 0;
+ uint8_t ch = 0;
+ uint8_t scratch[64];
+ BIO_MSG msg = {0};
+ size_t num_processed = 0;
+
+ if (!TEST_int_eq(RAND_bytes_ex(multi_libctx, &ch, 1, 64), 1))
+ goto err;
+
+ msg.data = scratch;
+ msg.data_len = sizeof(scratch);
+
+ /*
+ * We do not test for failure here as recvmmsg may fail if no sendmmsg
+ * has been called yet. The purpose of this code is to exercise tsan.
+ */
+ if (ch & 2)
+ r = BIO_sendmmsg(ch & 1 ? multi_bio2 : multi_bio1, &msg,
+ sizeof(BIO_MSG), 1, 0, &num_processed);
+ else
+ r = BIO_recvmmsg(ch & 1 ? multi_bio2 : multi_bio1, &msg,
+ sizeof(BIO_MSG), 1, 0, &num_processed);
+
+ ok = 1;
+err:
+ if (ok == 0)
+ multi_set_success(0);
+}
+
+static int test_bio_dgram_pair(void)
+{
+ int r;
+ BIO *bio1 = NULL, *bio2 = NULL;
+
+ r = BIO_new_bio_dgram_pair(&bio1, 0, &bio2, 0);
+ if (!TEST_int_eq(r, 1))
+ goto err;
+
+ multi_bio1 = bio1;
+ multi_bio2 = bio2;
+
+ r = thread_run_test(&test_bio_dgram_pair_worker,
+ MAXIMUM_THREADS, &test_bio_dgram_pair_worker,
+ 1, default_provider);
+
+err:
+ BIO_free(bio1);
+ BIO_free(bio2);
+ return r;
+}
+#endif
+
+static const char *pemdataraw[] = {
+ "-----BEGIN RSA PRIVATE KEY-----\n",
+ "MIIBOgIBAAJBAMFcGsaxxdgiuuGmCkVImy4h99CqT7jwY3pexPGcnUFtR2Fh36Bp\n",
+ "oncwtkZ4cAgtvd4Qs8PkxUdp6p/DlUmObdkCAwEAAQJAUR44xX6zB3eaeyvTRzms\n",
+ "kHADrPCmPWnr8dxsNwiDGHzrMKLN+i/HAam+97HxIKVWNDH2ba9Mf1SA8xu9dcHZ\n",
+ "AQIhAOHPCLxbtQFVxlnhSyxYeb7O323c3QulPNn3bhOipElpAiEA2zZpBE8ZXVnL\n",
+ "74QjG4zINlDfH+EOEtjJJ3RtaYDugvECIBtsQDxXytChsRgDQ1TcXdStXPcDppie\n",
+ "dZhm8yhRTTBZAiAZjE/U9rsIDC0ebxIAZfn3iplWh84yGB3pgUI3J5WkoQIhAInE\n",
+ "HTUY5WRj5riZtkyGnbm3DvF+1eMtO2lYV+OuLcfE\n",
+ "-----END RSA PRIVATE KEY-----\n",
+ NULL
+};
+
+static void test_pem_read_one(void)
+{
+ EVP_PKEY *key = NULL;
+ BIO *pem = NULL;
+ char *pemdata;
+ size_t len;
+
+ pemdata = glue_strings(pemdataraw, &len);
+ if (pemdata == NULL) {
+ multi_set_success(0);
+ goto err;
+ }
+
+ pem = BIO_new_mem_buf(pemdata, len);
+ if (pem == NULL) {
+ multi_set_success(0);
+ goto err;
+ }
+
+ key = PEM_read_bio_PrivateKey(pem, NULL, NULL, NULL);
+ if (key == NULL)
+ multi_set_success(0);
+
+ err:
+ EVP_PKEY_free(key);
+ BIO_free(pem);
+ OPENSSL_free(pemdata);
+}
+
+/* Test reading PEM files in multiple threads */
+static int test_pem_read(void)
+{
+ return thread_run_test(&test_pem_read_one, MAXIMUM_THREADS,
+ &test_pem_read_one, 1, default_provider);