blob: e638d6a676a69bc0f2cc96e722710deef951fd98 [file] [log] [blame]
Brian Silverman8fce7482020-01-05 13:18:21 -08001/*----------------------------------------------------------------------------*/
Austin Schuh1e69f942020-11-14 15:06:14 -08002/* Copyright (c) 2017-2020 FIRST. All Rights Reserved. */
Brian Silverman8fce7482020-01-05 13:18:21 -08003/* Open Source Software - may be modified and shared by FRC teams. The code */
4/* must be accompanied by the FIRST BSD license file in the root directory of */
5/* the project. */
6/*----------------------------------------------------------------------------*/
7
8#include "hal/Extensions.h"
9
Austin Schuh1e69f942020-11-14 15:06:14 -080010#include <vector>
11
Brian Silverman8fce7482020-01-05 13:18:21 -080012#include <wpi/Path.h>
13#include <wpi/SmallString.h>
14#include <wpi/StringRef.h>
15#include <wpi/raw_ostream.h>
Austin Schuh1e69f942020-11-14 15:06:14 -080016#include <wpi/spinlock.h>
Brian Silverman8fce7482020-01-05 13:18:21 -080017
18#if defined(WIN32) || defined(_WIN32)
19#include <windows.h>
20#else
21#include <dlfcn.h>
22#endif
23
24#if defined(WIN32) || defined(_WIN32)
25#define DELIM ';'
26#define HTYPE HMODULE
Austin Schuh1e69f942020-11-14 15:06:14 -080027#define DLOPEN(a) LoadLibraryA(a)
Brian Silverman8fce7482020-01-05 13:18:21 -080028#define DLSYM GetProcAddress
29#define DLCLOSE FreeLibrary
Austin Schuh1e69f942020-11-14 15:06:14 -080030#define DLERROR "error #" << GetLastError()
Brian Silverman8fce7482020-01-05 13:18:21 -080031#else
32#define DELIM ':'
33#define HTYPE void*
34#define PREFIX "lib"
35#define DLOPEN(a) dlopen(a, RTLD_LAZY)
36#define DLSYM dlsym
37#define DLCLOSE dlclose
Austin Schuh1e69f942020-11-14 15:06:14 -080038#define DLERROR dlerror()
Brian Silverman8fce7482020-01-05 13:18:21 -080039#endif
40
Austin Schuh1e69f942020-11-14 15:06:14 -080041static wpi::recursive_spinlock gExtensionRegistryMutex;
42static std::vector<std::pair<const char*, void*>> gExtensionRegistry;
43static std::vector<std::pair<void*, void (*)(void*, const char*, void*)>>
44 gExtensionListeners;
45
Brian Silverman8fce7482020-01-05 13:18:21 -080046namespace hal {
47namespace init {
48void InitializeExtensions() {}
49} // namespace init
50} // namespace hal
51
52static bool& GetShowNotFoundMessage() {
53 static bool showMsg = true;
54 return showMsg;
55}
56
57extern "C" {
58
59int HAL_LoadOneExtension(const char* library) {
60 int rc = 1; // It is expected and reasonable not to find an extra simulation
61 wpi::outs() << "HAL Extensions: Attempting to load: "
62 << wpi::sys::path::stem(library) << "\n";
63 wpi::outs().flush();
64 HTYPE handle = DLOPEN(library);
65#if !defined(WIN32) && !defined(_WIN32)
66 if (!handle) {
67 wpi::SmallString<128> libraryName("lib");
68 libraryName += library;
69#if defined(__APPLE__)
70 libraryName += ".dylib";
71#else
72 libraryName += ".so";
73#endif
Austin Schuh1e69f942020-11-14 15:06:14 -080074 wpi::outs() << "HAL Extensions: Load failed: " << DLERROR
75 << "\nTrying modified name: "
76 << wpi::sys::path::stem(libraryName) << "\n";
Brian Silverman8fce7482020-01-05 13:18:21 -080077 wpi::outs().flush();
78 handle = DLOPEN(libraryName.c_str());
79 }
80#endif
81 if (!handle) {
Austin Schuh1e69f942020-11-14 15:06:14 -080082 wpi::outs() << "HAL Extensions: Failed to load library: " << DLERROR
83 << '\n';
Brian Silverman8fce7482020-01-05 13:18:21 -080084 wpi::outs().flush();
85 return rc;
86 }
87
88 auto init = reinterpret_cast<halsim_extension_init_func_t*>(
89 DLSYM(handle, "HALSIM_InitExtension"));
90
91 if (init) rc = (*init)();
92
93 if (rc != 0) {
94 wpi::outs() << "HAL Extensions: Failed to load extension\n";
95 wpi::outs().flush();
96 DLCLOSE(handle);
97 } else {
98 wpi::outs() << "HAL Extensions: Successfully loaded extension\n";
99 wpi::outs().flush();
100 }
101 return rc;
102}
103
104int HAL_LoadExtensions(void) {
105 int rc = 1;
106 wpi::SmallVector<wpi::StringRef, 2> libraries;
107 const char* e = std::getenv("HALSIM_EXTENSIONS");
108 if (!e) {
109 if (GetShowNotFoundMessage()) {
110 wpi::outs() << "HAL Extensions: No extensions found\n";
111 wpi::outs().flush();
112 }
113 return rc;
114 }
115 wpi::StringRef env{e};
116 env.split(libraries, DELIM, -1, false);
117 for (auto& libref : libraries) {
118 wpi::SmallString<128> library(libref);
119 rc = HAL_LoadOneExtension(library.c_str());
120 if (rc < 0) break;
121 }
122 return rc;
123}
124
Austin Schuh1e69f942020-11-14 15:06:14 -0800125void HAL_RegisterExtension(const char* name, void* data) {
126 std::scoped_lock lock(gExtensionRegistryMutex);
127 gExtensionRegistry.emplace_back(name, data);
128 for (auto&& listener : gExtensionListeners)
129 listener.second(listener.first, name, data);
130}
131
132void HAL_RegisterExtensionListener(void* param,
133 void (*func)(void*, const char* name,
134 void* data)) {
135 std::scoped_lock lock(gExtensionRegistryMutex);
136 gExtensionListeners.emplace_back(param, func);
137 for (auto&& extension : gExtensionRegistry)
138 func(param, extension.first, extension.second);
139}
140
Brian Silverman8fce7482020-01-05 13:18:21 -0800141void HAL_SetShowExtensionsNotFoundMessages(HAL_Bool showMessage) {
142 GetShowNotFoundMessage() = showMessage;
143}
144
145} // extern "C"