diff --git a/src/test/modules/foo/Makefile b/src/test/modules/foo/Makefile new file mode 100644 index 0000000..da13e65 --- /dev/null +++ b/src/test/modules/foo/Makefile @@ -0,0 +1,18 @@ +# src/test/modules/foo/Makefile + +MODULES = foo + +EXTENSION = foo +DATA = foo--1.0.sql +PGFILEDESC = "foo -- a random testing/hacking extension" + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = src/test/modules/foo +top_builddir = ../../../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif diff --git a/src/test/modules/foo/foo--1.0.sql b/src/test/modules/foo/foo--1.0.sql new file mode 100644 index 0000000..6914e8a --- /dev/null +++ b/src/test/modules/foo/foo--1.0.sql @@ -0,0 +1,8 @@ +\echo Use "CREATE EXTENSION foo" to load this file. \quit + +CREATE FUNCTION barrier_test(workers int, loops int, impl int) +RETURNS void +AS 'MODULE_PATHNAME' +LANGUAGE C; + + diff --git a/src/test/modules/foo/foo.c b/src/test/modules/foo/foo.c new file mode 100644 index 0000000..bd267a2 --- /dev/null +++ b/src/test/modules/foo/foo.c @@ -0,0 +1,118 @@ +#include "postgres.h" + +#include "fmgr.h" +#include "funcapi.h" +#include "miscadmin.h" +#include "postmaster/bgworker.h" +#include "storage/barrier.h" +#include "storage/dsm.h" +#include "storage/proc.h" +#include "utils/builtins.h" +#include "utils/resowner.h" + +PG_MODULE_MAGIC; + +PG_FUNCTION_INFO_V1(barrier_test); + +extern Datum barrier_test_main(Datum); + +typedef struct barrier_test_state +{ + int loops; + int impl; + Barrier barrier; +} barrier_test_state; + +Datum +barrier_test_main(Datum arg) +{ + dsm_segment *segment; + barrier_test_state *state; + int i; + + BackgroundWorkerUnblockSignals(); + + CurrentResourceOwner = ResourceOwnerCreate(NULL, "barrier_test_main toplevel"); + + segment = dsm_attach(DatumGetInt32(arg)); + state = (barrier_test_state *) dsm_segment_address(segment); + + switch (state->impl) + { + case 0: + /* Use barrier.c. */ + for (i = 0; i < state->loops; ++i) + BarrierWait(&state->barrier); + break; + + case 1: + /* Insert semaphore-based barrier loop here! */ + break; + } + + dsm_detach(segment); + + return (Datum) 0; +} + +Datum +barrier_test(PG_FUNCTION_ARGS) +{ + int workers = PG_GETARG_INT32(0); + int loops = PG_GETARG_INT32(1); + int impl = PG_GETARG_INT32(2); + BackgroundWorkerHandle **handles; + barrier_test_state *state; + dsm_segment *segment; + int i; + + handles = palloc(sizeof(BackgroundWorkerHandle *) * workers); + + /* Set up basic state. */ + segment = dsm_create(sizeof(barrier_test_state), 0); + state = (barrier_test_state *) dsm_segment_address(segment); + state->loops = loops; + state->impl = impl; + + /* Set up per-implementation state. */ + switch (impl) + { + case 0: + BarrierInit(&state->barrier, workers); + break; + case 1: + /* Initialize semaphore-based version here. */ + break; + default: + elog(ERROR, "unknown impl"); + } + + /* Start workers. */ + for (i = 0; i < workers; ++i) + { + BackgroundWorker bgw; + + snprintf(bgw.bgw_name, sizeof(bgw.bgw_name), "worker%d", i); + bgw.bgw_flags = BGWORKER_SHMEM_ACCESS; + bgw.bgw_start_time = BgWorkerStart_PostmasterStart; + bgw.bgw_restart_time = BGW_NEVER_RESTART; + bgw.bgw_main = NULL; + snprintf(bgw.bgw_library_name, sizeof(bgw.bgw_library_name), + "foo"); + snprintf(bgw.bgw_function_name, sizeof(bgw.bgw_function_name), + "barrier_test_main"); + bgw.bgw_main_arg = Int32GetDatum(dsm_segment_handle(segment)); + bgw.bgw_notify_pid = MyProcPid; + + if (!RegisterDynamicBackgroundWorker(&bgw, &handles[i])) + elog(ERROR, "Can't start worker"); + } + + /* Wait for workers to complete. */ + for (i = 0; i < workers; ++i) + WaitForBackgroundWorkerShutdown(handles[i]); + + dsm_detach(segment); + + return (Datum) 0; +} diff --git a/src/test/modules/foo/foo.control b/src/test/modules/foo/foo.control new file mode 100644 index 0000000..af1b50a --- /dev/null +++ b/src/test/modules/foo/foo.control @@ -0,0 +1,4 @@ +comment = 'foo' +default_version = '1.0' +module_pathname = '$libdir/foo' +relocatable = true