Implement APIs missing on Windows. (#12)

This commit is contained in:
Kuba Ober 2019-12-28 11:44:24 -05:00 committed by W Snyder
parent c753904a3f
commit ac1cdf7cdf
5 changed files with 103 additions and 27 deletions

View File

@ -53,6 +53,10 @@
# include <sys/wait.h>
#endif
#if defined(_WIN32) || defined(__MINGW32__)
# include <io.h> // open, read, write, close
#endif
// If change this code, run a test with the below size set very small
//#define INFILTER_IPC_BUFSIZ 16
#define INFILTER_IPC_BUFSIZ (64*1024) // For debug, try this as a small number
@ -409,8 +413,7 @@ private:
|| errno == EWOULDBLOCK
#endif
) {
// cppcheck-suppress obsoleteFunctionsusleep
checkFilter(false); usleep(1000); continue;
checkFilter(false); V3Os::u_sleep(1000); continue;
} else { m_readEof = true; break; }
}
return out;
@ -448,8 +451,7 @@ private:
|| errno == EWOULDBLOCK
#endif
) {
// cppcheck-suppress obsoleteFunctionsusleep
checkFilter(false); usleep(1000); continue;
checkFilter(false); V3Os::u_sleep(1000); continue;
}
else break;
}

View File

@ -44,6 +44,10 @@
#include "config_rev.h"
#if defined(_WIN32) || defined(__MINGW32__)
# include <io.h> // open, close
#endif
//######################################################################
// V3 Internal state
@ -1364,11 +1368,12 @@ void V3Options::parseOptsFile(FileLine* fl, const string& filename, bool rel) {
string optdir = (rel ? V3Os::filenameDir(filename) : ".");
// Convert to argv style arg list and parse them
char* argv [args.size()+1];
for (unsigned i=0; i<args.size(); ++i) {
argv[i] = const_cast<char*>(args[i].c_str());
std::vector<char*> argv; argv.reserve(args.size()+1);
for (const string &arg : args) {
argv.push_back(const_cast<char*>(arg.c_str()));
}
parseOptsList(fl, optdir, args.size(), argv);
argv.push_back(nullptr); // argv is NULL-terminated
parseOptsList(fl, optdir, static_cast<int>(argv.size()-1), argv.data());
}
//======================================================================

View File

@ -18,6 +18,15 @@
//
//*************************************************************************
#if defined(_WIN32) || defined(__MINGW32__)
# ifndef PSAPI_VERSION
# define PSAPI_VERSION 1 // Needed for compatibility with Windows 7
# endif
#endif
#if defined(__MINGW32__)
# define MINGW_HAS_SECURE_API 1 // Needed to expose a "secure" POSIX-like API
#endif
#include "config_build.h"
#include "verilatedos.h"
@ -35,11 +44,18 @@
#include <iomanip>
#include <memory>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#if defined(_WIN32) || defined(__MINGW32__)
# include <winnt.h> // LONG for bcrypt.h on MINGW
# include <bcrypt.h> // BCryptGenRandom
# include <chrono>
# include <direct.h> // mkdir
# include <psapi.h> // GetProcessMemoryInfo
# include <thread>
#else
# include <sys/time.h>
# include <unistd.h> // usleep
#endif
@ -47,11 +63,23 @@
// Environment
string V3Os::getenvStr(const string& envvar, const string& defaultValue) {
#if defined(_MSC_VER)
// Note: MinGW does not offer _dupenv_s
char* envvalue;
if (_dupenv_s(&envvalue, nullptr, envvar.c_str()) == 0) {
const std::string result{envvalue};
free(envvalue);
return result;
} else {
return defaultValue;
}
#else
if (const char* envvalue = getenv(envvar.c_str())) {
return envvalue;
} else {
return defaultValue;
}
#endif
}
void V3Os::setenvStr(const string& envvar, const string& value, const string& why) {
@ -60,10 +88,12 @@ void V3Os::setenvStr(const string& envvar, const string& value, const string& wh
} else {
UINFO(1,"export "<<envvar<<"="<<value<<endl);
}
#if !defined(__MINGW32__) && (defined(_BSD_SOURCE) || (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L))
#if defined(_WIN32) || defined(__MINGW32__)
_putenv_s(envvar.c_str(), value.c_str());
#elif defined(_BSD_SOURCE) || (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L)
setenv(envvar.c_str(), value.c_str(), true);
#else
//setenv() replaced by putenv() in MinGW/Solaris environment. Prototype is different
//setenv() replaced by putenv() in Solaris environment. Prototype is different
//putenv() requires NAME=VALUE format
string vareq = envvar + "=" + value;
putenv(const_cast<char*>(vareq.c_str()));
@ -130,9 +160,9 @@ string V3Os::filenameSubstitute(const string& filename) {
v3fatal("Unmatched brackets in variable substitution in file: "+filename);
}
string envvar = filename.substr(pos+1, endpos-pos);
const char* envvalue = NULL;
if (envvar != "") envvalue = getenv(envvar.c_str());
if (envvalue) {
string envvalue;
if (!envvar.empty()) envvalue = getenvStr(envvar, {});
if (!envvalue.empty()) {
out += envvalue;
if (brackets==NONE) pos = endpos;
else pos = endpos+1;
@ -152,8 +182,8 @@ string V3Os::filenameRealPath(const string& filename) {
// If there is a ../ that goes down from the 'root' of this path it is preserved.
char retpath[PATH_MAX];
if (
#if defined( _MSC_VER ) || defined( __MINGW32__ )
::_fullpath(retpath, filename.c_str(), PATH_MAX)
#if defined(_WIN32) || defined(__MINGW32__)
_fullpath(retpath, filename.c_str(), PATH_MAX)
#else
realpath(filename.c_str(), retpath)
#endif
@ -188,7 +218,7 @@ string V3Os::getline(std::istream& is, char delim) {
void V3Os::createDir(const string& dirname) {
#if defined(_WIN32) || defined(__MINGW32__)
mkdir(dirname.c_str());
_mkdir(dirname.c_str());
#else
mkdir(dirname.c_str(), 0777);
#endif
@ -199,7 +229,11 @@ void V3Os::unlinkRegexp(const string& dir, const string& regexp) {
while (struct dirent* direntp = readdir(dirp)) {
if (VString::wildmatch(direntp->d_name, regexp.c_str())) {
string fullname = dir + "/" + string(direntp->d_name);
#if defined(_WIN32) || defined(__MINGW32__)
_unlink(fullname.c_str());
#else
unlink(fullname.c_str());
#endif
}
}
closedir(dirp);
@ -220,15 +254,24 @@ vluint64_t V3Os::rand64(vluint64_t* statep) {
}
string V3Os::trueRandom(size_t size) {
string data; data.reserve(size);
std::ifstream is ("/dev/urandom", std::ios::in | std::ios::binary);
char bytes[size];
if (!is.read(bytes, size)) {
v3fatal("Could not open /dev/urandom, no source of randomness. Try specifing a key instead.");
return "";
string result(size, '\xFF');
char *const data = const_cast<char*>(result.data());
// Note: std::string.data() returns a non-const Char* from C++17 onwards.
// For pre-C++17, this cast is OK in practice, even though it's UB.
#if defined(_WIN32) || defined(__MINGW32__)
NTSTATUS hr = BCryptGenRandom(NULL, reinterpret_cast<BYTE*>(data), size, BCRYPT_USE_SYSTEM_PREFERRED_RNG);
if (!BCRYPT_SUCCESS(hr)) {
v3fatal("Could not acquire random data.");
}
data.append(bytes, size);
return data;
#else
std::ifstream is ("/dev/urandom", std::ios::in | std::ios::binary);
// This read uses the size of the buffer.
// Flawfinder: ignore
if (!is.read(data, size)) {
v3fatal("Could not open /dev/urandom, no source of randomness. Try specifing a key instead.");
}
#endif
return result;
}
//######################################################################
@ -236,7 +279,13 @@ string V3Os::trueRandom(size_t size) {
uint64_t V3Os::timeUsecs() {
#if defined(_WIN32) || defined(__MINGW32__)
return 0;
// Microseconds between 1601-01-01 00:00:00 UTC and 1970-01-01 00:00:00 UTC
static const uint64_t EPOCH_DIFFERENCE_USECS = 11644473600000000ull;
FILETIME ft; // contains number of 0.1us intervals since the beginning of 1601 UTC.
GetSystemTimeAsFileTime(&ft);
uint64_t us = ((static_cast<uint64_t>(ft.dwHighDateTime) << 32) + ft.dwLowDateTime + 5ull) / 10ull;
return us - EPOCH_DIFFERENCE_USECS;
#else
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
timeval tv;
@ -247,6 +296,12 @@ uint64_t V3Os::timeUsecs() {
uint64_t V3Os::memUsageBytes() {
#if defined(_WIN32) || defined(__MINGW32__)
HANDLE process = GetCurrentProcess();
PROCESS_MEMORY_COUNTERS pmc;
if (GetProcessMemoryInfo(process, &pmc, sizeof(pmc))) {
// The best we can do using simple Windows APIs is to get the size of the working set.
return pmc.WorkingSetSize;
}
return 0;
#else
// Highly unportable. Sorry
@ -266,3 +321,13 @@ uint64_t V3Os::memUsageBytes() {
return (text + data) * getpagesize();
#endif
}
void V3Os::u_sleep(int64_t usec) {
#if defined(_WIN32) || defined(__MINGW32__)
std::this_thread::sleep_for(std::chrono::microseconds(usec));
#else
// cppcheck-suppress obsoleteFunctionsusleep
// Flawfinder: ignore
::usleep(usec);
#endif
}

View File

@ -58,7 +58,8 @@ public:
static vluint64_t rand64(vluint64_t* statep);
static string trueRandom(size_t size);
// METHODS (performance)
// METHODS (time & performance)
static void u_sleep(int64_t usec); ///< Sleep for a given number of microseconds.
static uint64_t timeUsecs(); ///< Return wall time since epoch in microseconds, or 0 if not implemented
static uint64_t memUsageBytes(); ///< Return memory usage in bytes, or 0 if not implemented
};

View File

@ -27,6 +27,9 @@
#include "V3PreProc.h"
#include "V3PreLex.h"
#ifdef _WIN32
# include <io.h> // for isatty
#endif
V3PreLex* V3PreLex::s_currentLexp = NULL; // Current lexing point