aboutsummaryrefslogtreecommitdiff
path: root/src/backend/jit/jit.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/jit/jit.c')
-rw-r--r--src/backend/jit/jit.c156
1 files changed, 156 insertions, 0 deletions
diff --git a/src/backend/jit/jit.c b/src/backend/jit/jit.c
new file mode 100644
index 00000000000..6c842a0fe9f
--- /dev/null
+++ b/src/backend/jit/jit.c
@@ -0,0 +1,156 @@
+/*-------------------------------------------------------------------------
+ *
+ * jit.c
+ * Provider independent JIT infrastructure.
+ *
+ * Code related to loading JIT providers, redirecting calls into JIT providers
+ * and error handling. No code specific to a specific JIT implementation
+ * should end up here.
+ *
+ *
+ * Copyright (c) 2016-2018, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ * src/backend/jit/jit.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+
+#include "fmgr.h"
+#include "jit/jit.h"
+#include "miscadmin.h"
+#include "utils/resowner_private.h"
+#include "utils/fmgrprotos.h"
+
+
+/* GUCs */
+bool jit_enabled = true;
+char *jit_provider = "llvmjit";
+
+static JitProviderCallbacks provider;
+static bool provider_successfully_loaded = false;
+static bool provider_failed_loading = false;
+
+
+static bool provider_init(void);
+static bool file_exists(const char *name);
+
+
+/*
+ * SQL level function returning whether JIT is available in the current
+ * backend. Will attempt to load JIT provider if necessary.
+ */
+Datum
+pg_jit_available(PG_FUNCTION_ARGS)
+{
+ PG_RETURN_BOOL(provider_init());
+}
+
+
+/*
+ * Return whether a JIT provider has successfully been loaded, caching the
+ * result.
+ */
+static bool
+provider_init(void)
+{
+ char path[MAXPGPATH];
+ JitProviderInit init;
+
+ /* don't even try to load if not enabled */
+ if (!jit_enabled)
+ return false;
+
+ /*
+ * Don't retry loading after failing - attempting to load JIT provider
+ * isn't cheap.
+ */
+ if (provider_failed_loading)
+ return false;
+ if (provider_successfully_loaded)
+ return true;
+
+ /*
+ * Check whether shared library exists. We do that check before actually
+ * attempting to load the shared library (via load_external_function()),
+ * because that'd error out in case the shlib isn't available.
+ */
+ snprintf(path, MAXPGPATH, "%s/%s%s", pkglib_path, jit_provider, DLSUFFIX);
+ elog(DEBUG1, "probing availability of JIT provider at %s", path);
+ if (!file_exists(path))
+ {
+ elog(DEBUG1,
+ "provider not available, disabling JIT for current session");
+ provider_failed_loading = true;
+ return false;
+ }
+
+ /*
+ * If loading functions fails, signal failure. We do so because
+ * load_external_function() might error out despite the above check if
+ * e.g. the library's dependencies aren't installed. We want to signal
+ * ERROR in that case, so the user is notified, but we don't want to
+ * continually retry.
+ */
+ provider_failed_loading = true;
+
+ /* and initialize */
+ init = (JitProviderInit)
+ load_external_function(path, "_PG_jit_provider_init", true, NULL);
+ init(&provider);
+
+ provider_successfully_loaded = true;
+ provider_failed_loading = false;
+
+ elog(DEBUG1, "successfully loaded JIT provider in current session");
+
+ return true;
+}
+
+/*
+ * Reset JIT provider's error handling. This'll be called after an error has
+ * been thrown and the main-loop has re-established control.
+ */
+void
+jit_reset_after_error(void)
+{
+ if (provider_successfully_loaded)
+ provider.reset_after_error();
+}
+
+/*
+ * Release resources required by one JIT context.
+ */
+void
+jit_release_context(JitContext *context)
+{
+ if (provider_successfully_loaded)
+ provider.release_context(context);
+
+ ResourceOwnerForgetJIT(context->resowner, PointerGetDatum(context));
+ pfree(context);
+}
+
+static bool
+file_exists(const char *name)
+{
+ struct stat st;
+
+ AssertArg(name != NULL);
+
+ if (stat(name, &st) == 0)
+ return S_ISDIR(st.st_mode) ? false : true;
+ else if (!(errno == ENOENT || errno == ENOTDIR))
+ ereport(ERROR,
+ (errcode_for_file_access(),
+ errmsg("could not access file \"%s\": %m", name)));
+
+ return false;
+}