From 97b1bc1ac379038701d1b57f8f64149b13fc351b Mon Sep 17 00:00:00 2001
From: Masahiro Ikeda <masahiro.ikeda.us@hco.ntt.co.jp>
Date: Thu, 15 Jun 2023 11:24:01 +0900
Subject: [PATCH 1/3] Add a extension to test custom wait event

Since the extension is used for only development, it's not intended
to be commited in master branch.
---
 contrib/inject_wait_event/.gitignore          |   1 +
 contrib/inject_wait_event/Makefile            |  24 ++++
 .../inject_wait_event--1.0.sql                |  12 ++
 contrib/inject_wait_event/inject_wait_event.c | 119 ++++++++++++++++++
 .../inject_wait_event.control                 |   4 +
 5 files changed, 160 insertions(+)
 create mode 100644 contrib/inject_wait_event/.gitignore
 create mode 100644 contrib/inject_wait_event/Makefile
 create mode 100644 contrib/inject_wait_event/inject_wait_event--1.0.sql
 create mode 100644 contrib/inject_wait_event/inject_wait_event.c
 create mode 100644 contrib/inject_wait_event/inject_wait_event.control

diff --git a/contrib/inject_wait_event/.gitignore b/contrib/inject_wait_event/.gitignore
new file mode 100644
index 0000000000..43cea6480a
--- /dev/null
+++ b/contrib/inject_wait_event/.gitignore
@@ -0,0 +1 @@
+inject_wait_event
\ No newline at end of file
diff --git a/contrib/inject_wait_event/Makefile b/contrib/inject_wait_event/Makefile
new file mode 100644
index 0000000000..40221e7ac2
--- /dev/null
+++ b/contrib/inject_wait_event/Makefile
@@ -0,0 +1,24 @@
+# contrib/inject_wait_event/Makefile
+
+MODULE_big	= inject_wait_event
+
+OBJS = \
+	$(WIN32RES) \
+	inject_wait_event.o
+
+EXTENSION = inject_wait_event
+DATA = inject_wait_event--1.0.sql
+PGFILEDESC = "inject wait event for test"
+
+TAP_TESTS = 0
+
+ifdef USE_PGXS
+PG_CONFIG = pg_config
+PGXS := $(shell $(PG_CONFIG) --pgxs)
+include $(PGXS)
+else
+subdir = contrib/inject_wait_event
+top_builddir = ../..
+include $(top_builddir)/src/Makefile.global
+include $(top_srcdir)/contrib/contrib-global.mk
+endif
diff --git a/contrib/inject_wait_event/inject_wait_event--1.0.sql b/contrib/inject_wait_event/inject_wait_event--1.0.sql
new file mode 100644
index 0000000000..8ebab415c3
--- /dev/null
+++ b/contrib/inject_wait_event/inject_wait_event--1.0.sql
@@ -0,0 +1,12 @@
+/* contrib/inject_wait_event/inject_wait_event--1.0.sql */
+
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION inject_wait_event" to load this file. \quit
+
+--
+-- inject_wait_event()
+--
+CREATE FUNCTION inject_wait_event()
+RETURNS VOID
+AS 'MODULE_PATHNAME', 'inject_wait_event'
+LANGUAGE C STRICT PARALLEL RESTRICTED;
diff --git a/contrib/inject_wait_event/inject_wait_event.c b/contrib/inject_wait_event/inject_wait_event.c
new file mode 100644
index 0000000000..b9673808d3
--- /dev/null
+++ b/contrib/inject_wait_event/inject_wait_event.c
@@ -0,0 +1,119 @@
+/*-------------------------------------------------------------------------
+ *
+ * inject_wait_event.c
+ *     Support a function to inject wait events for test
+ *
+ * Since the extension assumes to be used for only development,
+ * don't commit the master branch.
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "fmgr.h"
+#include "miscadmin.h"
+#include "storage/ipc.h"
+#include "storage/lwlock.h"
+#include "storage/latch.h"
+#include "storage/shmem.h"
+#include "utils/wait_event.h"
+
+PG_MODULE_MAGIC;
+
+PG_FUNCTION_INFO_V1(inject_wait_event);
+
+typedef struct state
+{
+	uint32		custom_wait_event;	/* custom a wait event */
+}			state;
+
+static shmem_request_hook_type prev_shmem_request_hook = NULL;
+static shmem_request_hook_type prev_shmem_startup_hook = NULL;
+
+static state * ss = NULL;
+
+static void shmem_request(void);
+static void shmem_startup(void);
+static void shmem_startup(void);
+static Size memsize(void);
+
+void
+_PG_init(void)
+{
+	if (!process_shared_preload_libraries_in_progress)
+		return;
+
+	prev_shmem_request_hook = shmem_request_hook;
+	shmem_request_hook = shmem_request;
+	prev_shmem_startup_hook = shmem_startup_hook;
+	shmem_startup_hook = shmem_startup;
+}
+
+static void
+shmem_request(void)
+{
+	if (prev_shmem_request_hook)
+		prev_shmem_request_hook();
+
+	RequestAddinShmemSpace(memsize());
+
+	/* define a custom wait event */
+	RequestNamedExtensionWaitEventTranche("custom_wait_event");
+}
+
+static void
+shmem_startup(void)
+{
+	bool		found;
+
+	if (prev_shmem_startup_hook)
+		prev_shmem_startup_hook();
+
+	ss = NULL;
+
+	/*
+	 * Create or attach to the shared memory state
+	 */
+	LWLockAcquire(AddinShmemInitLock, LW_EXCLUSIVE);
+	ss = ShmemInitStruct("inject_wait_event",
+						 sizeof(state),
+						 &found);
+
+	if (!found)
+	{
+		ss->custom_wait_event = GetNamedExtensionWaitEventTranche("custom_wait_event");
+	}
+	LWLockRelease(AddinShmemInitLock);
+
+	return;
+}
+
+static Size
+memsize(void)
+{
+	Size		size;
+
+	size = MAXALIGN(sizeof(state));
+
+	return size;
+}
+
+Datum
+inject_wait_event(PG_FUNCTION_ARGS)
+{
+	/* default */
+	(void) WaitLatch(MyLatch,
+					 WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
+					 10L * 1000,	/* 10s */
+					 PG_WAIT_EXTENSION);
+	ResetLatch(MyLatch);
+
+	/* custom wait event */
+	(void) WaitLatch(MyLatch,
+					 WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
+					 10L * 1000,	/* 10s */
+					 ss->custom_wait_event);
+	ResetLatch(MyLatch);
+
+	PG_RETURN_VOID();
+}
diff --git a/contrib/inject_wait_event/inject_wait_event.control b/contrib/inject_wait_event/inject_wait_event.control
new file mode 100644
index 0000000000..3f1132185e
--- /dev/null
+++ b/contrib/inject_wait_event/inject_wait_event.control
@@ -0,0 +1,4 @@
+# inject_wait_event extension
+comment = 'a function for injecting wait event for test'
+default_version = '1.0'
+module_pathname = '$libdir/inject_wait_event'
-- 
2.25.1

