mirror of
https://github.com/KhronosGroup/OpenCL-CTS.git
synced 2026-03-23 15:39:03 +00:00
Initial open source release of OpenCL 2.1 CTS.
This commit is contained in:
564
test_common/harness/os_helpers.cpp
Normal file
564
test_common/harness/os_helpers.cpp
Normal file
@@ -0,0 +1,564 @@
|
||||
//
|
||||
// Copyright (c) 2017 The Khronos Group Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
#include "os_helpers.h"
|
||||
#include "errorHelpers.h"
|
||||
|
||||
// =================================================================================================
|
||||
// C++ interface.
|
||||
// =================================================================================================
|
||||
|
||||
#include <cerrno> // errno, error constants
|
||||
#include <climits> // PATH_MAX
|
||||
#include <cstdlib> // abort, _splitpath, _makepath
|
||||
#include <cstring> // strdup, strerror_r
|
||||
#include <sstream>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#define CHECK_PTR( ptr ) \
|
||||
if ( (ptr) == NULL ) { \
|
||||
abort(); \
|
||||
}
|
||||
|
||||
typedef std::vector< char > buffer_t;
|
||||
|
||||
#if ! defined( PATH_MAX )
|
||||
#define PATH_MAX 1000
|
||||
#endif
|
||||
|
||||
int const _size = PATH_MAX + 1; // Initial buffer size for path.
|
||||
int const _count = 8; // How many times we will try to double buffer size.
|
||||
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
// MacOS X
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
|
||||
#if defined( __APPLE__ )
|
||||
|
||||
|
||||
#include <mach-o/dyld.h> // _NSGetExecutablePath
|
||||
#include <libgen.h> // dirname
|
||||
|
||||
|
||||
static
|
||||
std::string
|
||||
_err_msg(
|
||||
int err, // Error number (e. g. errno).
|
||||
int level // Nesting level, for avoiding infinite recursion.
|
||||
) {
|
||||
|
||||
/*
|
||||
There are 3 incompatible versions of strerror_r:
|
||||
|
||||
char * strerror_r( int, char *, size_t ); // GNU version
|
||||
int strerror_r( int, char *, size_t ); // BSD version
|
||||
int strerror_r( int, char *, size_t ); // XSI version
|
||||
|
||||
BSD version returns error code, while XSI version returns 0 or -1 and sets errno.
|
||||
|
||||
*/
|
||||
|
||||
// BSD version of strerror_r.
|
||||
buffer_t buffer( 100 );
|
||||
int count = _count;
|
||||
for ( ; ; ) {
|
||||
int rc = strerror_r( err, & buffer.front(), buffer.size() );
|
||||
if ( rc == EINVAL ) {
|
||||
// Error code is not recognized, but anyway we got the message.
|
||||
return & buffer.front();
|
||||
} else if ( rc == ERANGE ) {
|
||||
// Buffer is not enough.
|
||||
if ( count > 0 ) {
|
||||
// Enlarge the buffer.
|
||||
-- count;
|
||||
buffer.resize( buffer.size() * 2 );
|
||||
} else {
|
||||
std::stringstream ostr;
|
||||
ostr
|
||||
<< "Error " << err << " "
|
||||
<< "(Getting error message failed: "
|
||||
<< "Buffer of " << buffer.size() << " bytes is still too small"
|
||||
<< ")";
|
||||
return ostr.str();
|
||||
}; // if
|
||||
} else if ( rc == 0 ) {
|
||||
// We got the message.
|
||||
return & buffer.front();
|
||||
} else {
|
||||
std::stringstream ostr;
|
||||
ostr
|
||||
<< "Error " << err << " "
|
||||
<< "(Getting error message failed: "
|
||||
<< ( level < 2 ? _err_msg( rc, level + 1 ) : "Oops" )
|
||||
<< ")";
|
||||
return ostr.str();
|
||||
}; // if
|
||||
}; // forever
|
||||
|
||||
} // _err_msg
|
||||
|
||||
|
||||
std::string
|
||||
dir_sep(
|
||||
) {
|
||||
return "/";
|
||||
} // dir_sep
|
||||
|
||||
|
||||
std::string
|
||||
exe_path(
|
||||
) {
|
||||
buffer_t path( _size );
|
||||
int count = _count;
|
||||
for ( ; ; ) {
|
||||
uint32_t size = path.size();
|
||||
int rc = _NSGetExecutablePath( & path.front(), & size );
|
||||
if ( rc == 0 ) {
|
||||
break;
|
||||
}; // if
|
||||
if ( count > 0 ) {
|
||||
-- count;
|
||||
path.resize( size );
|
||||
} else {
|
||||
log_error(
|
||||
"ERROR: Getting executable path failed: "
|
||||
"_NSGetExecutablePath failed: Buffer of %lu bytes is still too small\n",
|
||||
(unsigned long) path.size()
|
||||
);
|
||||
exit( 2 );
|
||||
}; // if
|
||||
}; // forever
|
||||
return & path.front();
|
||||
} // exe_path
|
||||
|
||||
|
||||
std::string
|
||||
exe_dir(
|
||||
) {
|
||||
std::string path = exe_path();
|
||||
// We cannot pass path.c_str() to `dirname' bacause `dirname' modifies its argument.
|
||||
buffer_t buffer( path.c_str(), path.c_str() + path.size() + 1 ); // Copy with trailing zero.
|
||||
return dirname( & buffer.front() );
|
||||
} // exe_dir
|
||||
|
||||
|
||||
#endif // __APPLE__
|
||||
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
// Linux
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
|
||||
#if defined( __linux__ )
|
||||
|
||||
|
||||
#include <cerrno> // errno
|
||||
#include <libgen.h> // dirname
|
||||
#include <unistd.h> // readlink
|
||||
|
||||
|
||||
static
|
||||
std::string
|
||||
_err_msg(
|
||||
int err,
|
||||
int level
|
||||
) {
|
||||
|
||||
/*
|
||||
There are 3 incompatible versions of strerror_r:
|
||||
|
||||
char * strerror_r( int, char *, size_t ); // GNU version
|
||||
int strerror_r( int, char *, size_t ); // BSD version
|
||||
int strerror_r( int, char *, size_t ); // XSI version
|
||||
|
||||
BSD version returns error code, while XSI version returns 0 or -1 and sets errno.
|
||||
|
||||
*/
|
||||
|
||||
#if defined(__ANDROID__) || ( ( _POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600 ) && ! _GNU_SOURCE )
|
||||
|
||||
// XSI version of strerror_r.
|
||||
#warning Not tested!
|
||||
buffer_t buffer( 200 );
|
||||
int count = _count;
|
||||
for ( ; ; ) {
|
||||
int rc = strerror_r( err, & buffer.front(), buffer.size() );
|
||||
if ( rc == -1 ) {
|
||||
int _err = errno;
|
||||
if ( _err == ERANGE ) {
|
||||
if ( count > 0 ) {
|
||||
// Enlarge the buffer.
|
||||
-- count;
|
||||
buffer.resize( buffer.size() * 2 );
|
||||
} else {
|
||||
std::stringstream ostr;
|
||||
ostr
|
||||
<< "Error " << err << " "
|
||||
<< "(Getting error message failed: "
|
||||
<< "Buffer of " << buffer.size() << " bytes is still too small"
|
||||
<< ")";
|
||||
return ostr.str();
|
||||
}; // if
|
||||
} else {
|
||||
std::stringstream ostr;
|
||||
ostr
|
||||
<< "Error " << err << " "
|
||||
<< "(Getting error message failed: "
|
||||
<< ( level < 2 ? _err_msg( _err, level + 1 ) : "Oops" )
|
||||
<< ")";
|
||||
return ostr.str();
|
||||
}; // if
|
||||
} else {
|
||||
// We got the message.
|
||||
return & buffer.front();
|
||||
}; // if
|
||||
}; // forever
|
||||
|
||||
#else
|
||||
|
||||
// GNU version of strerror_r.
|
||||
char buffer[ 2000 ];
|
||||
return strerror_r( err, buffer, sizeof( buffer ) );
|
||||
|
||||
#endif
|
||||
|
||||
} // _err_msg
|
||||
|
||||
|
||||
std::string
|
||||
dir_sep(
|
||||
) {
|
||||
return "/";
|
||||
} // dir_sep
|
||||
|
||||
|
||||
std::string
|
||||
exe_path(
|
||||
) {
|
||||
|
||||
static std::string const exe = "/proc/self/exe";
|
||||
|
||||
buffer_t path( _size );
|
||||
int count = _count; // Max number of iterations.
|
||||
|
||||
for ( ; ; ) {
|
||||
|
||||
ssize_t len = readlink( exe.c_str(), & path.front(), path.size() );
|
||||
|
||||
if ( len < 0 ) {
|
||||
// Oops.
|
||||
int err = errno;
|
||||
log_error(
|
||||
"ERROR: Getting executable path failed: "
|
||||
"Reading symlink `%s' failed: %s\n",
|
||||
exe.c_str(), err_msg( err ).c_str()
|
||||
);
|
||||
exit( 2 );
|
||||
}; // if
|
||||
|
||||
if ( len < path.size() ) {
|
||||
// We got the path.
|
||||
path.resize( len );
|
||||
break;
|
||||
}; // if
|
||||
|
||||
// Oops, buffer is too small.
|
||||
if ( count > 0 ) {
|
||||
-- count;
|
||||
// Enlarge the buffer.
|
||||
path.resize( path.size() * 2 );
|
||||
} else {
|
||||
log_error(
|
||||
"ERROR: Getting executable path failed: "
|
||||
"Reading symlink `%s' failed: Buffer of %lu bytes is still too small\n",
|
||||
exe.c_str(),
|
||||
(unsigned long) path.size()
|
||||
);
|
||||
exit( 2 );
|
||||
}; // if
|
||||
|
||||
}; // forever
|
||||
|
||||
return std::string( & path.front(), path.size() );
|
||||
|
||||
} // exe_path
|
||||
|
||||
|
||||
std::string
|
||||
exe_dir(
|
||||
) {
|
||||
std::string path = exe_path();
|
||||
// We cannot pass path.c_str() to `dirname' bacause `dirname' modifies its argument.
|
||||
buffer_t buffer( path.c_str(), path.c_str() + path.size() + 1 ); // Copy with trailing zero.
|
||||
return dirname( & buffer.front() );
|
||||
} // exe_dir
|
||||
|
||||
#endif // __linux__
|
||||
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
// MS Windows
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
|
||||
#if defined( _WIN32 )
|
||||
|
||||
|
||||
#include <windows.h>
|
||||
#if defined( max )
|
||||
#undef max
|
||||
#endif
|
||||
|
||||
#include <cctype>
|
||||
#include <algorithm>
|
||||
|
||||
|
||||
static
|
||||
std::string
|
||||
_err_msg(
|
||||
int err,
|
||||
int level
|
||||
) {
|
||||
|
||||
std::string msg;
|
||||
|
||||
LPSTR buffer = NULL;
|
||||
DWORD flags =
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS;
|
||||
|
||||
DWORD len =
|
||||
FormatMessageA(
|
||||
flags,
|
||||
NULL,
|
||||
err,
|
||||
LANG_USER_DEFAULT,
|
||||
reinterpret_cast< LPSTR >( & buffer ),
|
||||
0,
|
||||
NULL
|
||||
);
|
||||
|
||||
if ( buffer == NULL || len == 0 ) {
|
||||
|
||||
int _err = GetLastError();
|
||||
char str[1024] = { 0 };
|
||||
snprintf(str, sizeof(str), "Error 0x%08x (Getting error message failed: %s )", err, ( level < 2 ? _err_msg( _err, level + 1 ).c_str() : "Oops" ));
|
||||
msg = std::string(str);
|
||||
|
||||
} else {
|
||||
|
||||
// Trim trailing whitespace (including `\r' and `\n').
|
||||
while ( len > 0 && isspace( buffer[ len - 1 ] ) ) {
|
||||
-- len;
|
||||
}; // while
|
||||
|
||||
// Drop trailing full stop.
|
||||
if ( len > 0 && buffer[ len - 1 ] == '.' ) {
|
||||
-- len;
|
||||
}; // if
|
||||
|
||||
msg.assign( buffer, len );
|
||||
|
||||
}; //if
|
||||
|
||||
if ( buffer != NULL ) {
|
||||
LocalFree( buffer );
|
||||
}; // if
|
||||
|
||||
return msg;
|
||||
|
||||
} // _get_err_msg
|
||||
|
||||
|
||||
std::string
|
||||
dir_sep(
|
||||
) {
|
||||
return "\\";
|
||||
} // dir_sep
|
||||
|
||||
|
||||
std::string
|
||||
exe_path(
|
||||
) {
|
||||
|
||||
buffer_t path( _size );
|
||||
int count = _count;
|
||||
|
||||
for ( ; ; ) {
|
||||
|
||||
DWORD len = GetModuleFileNameA( NULL, & path.front(), path.size() );
|
||||
|
||||
if ( len == 0 ) {
|
||||
int err = GetLastError();
|
||||
log_error( "ERROR: Getting executable path failed: %s\n", err_msg( err ).c_str() );
|
||||
exit( 2 );
|
||||
}; // if
|
||||
|
||||
if ( len < path.size() ) {
|
||||
path.resize( len );
|
||||
break;
|
||||
}; // if
|
||||
|
||||
// Buffer too small.
|
||||
if ( count > 0 ) {
|
||||
-- count;
|
||||
path.resize( path.size() * 2 );
|
||||
} else {
|
||||
log_error(
|
||||
"ERROR: Getting executable path failed: "
|
||||
"Buffer of %lu bytes is still too small\n",
|
||||
(unsigned long) path.size()
|
||||
);
|
||||
exit( 2 );
|
||||
}; // if
|
||||
|
||||
}; // forever
|
||||
|
||||
return std::string( & path.front(), path.size() );
|
||||
|
||||
} // exe_path
|
||||
|
||||
|
||||
std::string
|
||||
exe_dir(
|
||||
) {
|
||||
|
||||
std::string exe = exe_path();
|
||||
int count = 0;
|
||||
|
||||
// Splitting path into components.
|
||||
buffer_t drv( _MAX_DRIVE );
|
||||
buffer_t dir( _MAX_DIR );
|
||||
count = _count;
|
||||
#if defined(_MSC_VER)
|
||||
for ( ; ; ) {
|
||||
int rc =
|
||||
_splitpath_s(
|
||||
exe.c_str(),
|
||||
& drv.front(), drv.size(),
|
||||
& dir.front(), dir.size(),
|
||||
NULL, 0, // We need neither name
|
||||
NULL, 0 // nor extension
|
||||
);
|
||||
if ( rc == 0 ) {
|
||||
break;
|
||||
} else if ( rc == ERANGE ) {
|
||||
if ( count > 0 ) {
|
||||
-- count;
|
||||
// Buffer is too small, but it is not clear which one.
|
||||
// So we have to enlarge all.
|
||||
drv.resize( drv.size() * 2 );
|
||||
dir.resize( dir.size() * 2 );
|
||||
} else {
|
||||
log_error(
|
||||
"ERROR: Getting executable path failed: "
|
||||
"Splitting path `%s' to components failed: "
|
||||
"Buffers of %lu and %lu bytes are still too small\n",
|
||||
exe.c_str(),
|
||||
(unsigned long) drv.size(),
|
||||
(unsigned long) dir.size()
|
||||
);
|
||||
exit( 2 );
|
||||
}; // if
|
||||
} else {
|
||||
log_error(
|
||||
"ERROR: Getting executable path failed: "
|
||||
"Splitting path `%s' to components failed: %s\n",
|
||||
exe.c_str(),
|
||||
err_msg( rc ).c_str()
|
||||
);
|
||||
exit( 2 );
|
||||
}; // if
|
||||
}; // forever
|
||||
|
||||
#else // __MINGW32__
|
||||
|
||||
// MinGW does not have the "secure" _splitpath_s, use the insecure version instead.
|
||||
_splitpath(
|
||||
exe.c_str(),
|
||||
& drv.front(),
|
||||
& dir.front(),
|
||||
NULL, // We need neither name
|
||||
NULL // nor extension
|
||||
);
|
||||
#endif // __MINGW32__
|
||||
|
||||
// Combining components back to path.
|
||||
// I failed with "secure" `_makepath_s'. If buffer is too small, instead of returning
|
||||
// ERANGE, `_makepath_s' pops up dialog box and offers to debug the program. D'oh!
|
||||
// So let us try to guess the size of result and go with insecure `_makepath'.
|
||||
buffer_t path( std::max( drv.size() + dir.size(), size_t( _MAX_PATH ) ) + 10 );
|
||||
_makepath( & path.front(), & drv.front(), & dir.front(), NULL, NULL );
|
||||
|
||||
return & path.front();
|
||||
|
||||
} // exe_dir
|
||||
|
||||
|
||||
#endif // _WIN32
|
||||
|
||||
|
||||
std::string
|
||||
err_msg(
|
||||
int err
|
||||
) {
|
||||
|
||||
return _err_msg( err, 0 );
|
||||
|
||||
} // err_msg
|
||||
|
||||
|
||||
// =================================================================================================
|
||||
// C interface.
|
||||
// =================================================================================================
|
||||
|
||||
|
||||
char *
|
||||
get_err_msg(
|
||||
int err
|
||||
) {
|
||||
char * msg = strdup( err_msg( err ).c_str() );
|
||||
CHECK_PTR( msg );
|
||||
return msg;
|
||||
} // get_err_msg
|
||||
|
||||
|
||||
char *
|
||||
get_dir_sep(
|
||||
) {
|
||||
char * sep = strdup( dir_sep().c_str() );
|
||||
CHECK_PTR( sep );
|
||||
return sep;
|
||||
} // get_dir_sep
|
||||
|
||||
|
||||
char *
|
||||
get_exe_path(
|
||||
) {
|
||||
char * path = strdup( exe_path().c_str() );
|
||||
CHECK_PTR( path );
|
||||
return path;
|
||||
} // get_exe_path
|
||||
|
||||
|
||||
char *
|
||||
get_exe_dir(
|
||||
) {
|
||||
char * dir = strdup( exe_dir().c_str() );
|
||||
CHECK_PTR( dir );
|
||||
return dir;
|
||||
} // get_exe_dir
|
||||
|
||||
|
||||
// end of file //
|
||||
Reference in New Issue
Block a user