I'm taking my first steps into both C++ and OpenCL to perform parallel computing, but I'm running into a bug attempting to pass a listener function to clCreateContext. My program (not shown) is crashing without error, so I need to add a function to forward OpenCL errors to stdout/stderr. The clCreateContext function has an argument for a function pointer that can be set to forward error messages to stdout or stderr. I get a compile time error however using Codeblocks/MinGW:
invalid conversion from 'void (*)(const char*, const void*, size_t, void*)' to
'void (*)(const char*, const void*, size_t, void*)'
I've replicated the problem in the code below:
#include <stdlib.h>
#include <stdio.h>
#include <CL\cl.h>
void pfn_notify(const char *errinfo, const void *private_info, size_t cb, void *user_data)
{
fprintf(stderr, "OpenCL Error (via pfn_notify): %s\n", errinfo);
}
int main()
{
/*Get platform and device info*/
cl_platform_id platform_id = NULL;
cl_uint ret_num_platforms;
cl_int ret = clGetPlatformIDs(1, &platform_id, &ret_num_platforms);
cl_device_id device_id = NULL;
cl_uint ret_num_devices;
ret = clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_GPU, 1, &device_id, &ret_num_devices);
/*Create openCL context*/
cl_context context = clCreateContext(NULL, 1, &device_id, &pfn_notify, NULL, &ret);
/*Some line after this throws an error*/
}
I have seen code examples of using this exact method and pfn_notify that have worked, and am not sure why my program isn't even compiling. Thanks in advance, and let me know if there's anything else I can post to help.
You need to declare your function as
void CL_CALLBACK pfn_notify(.....
As the commentors point out; if this code is in a C++ file then it also needs to be:
extern "C" void CL_CALLBACK pfn_notify(.....
Related
I want to override open from libc using LD_PRELOAD:
#include <dlfcn.h>
#include <sys/stat.h>
extern "C" {
int open(const char *path, int flags, mode_t mode)
{
int (*originalOpen)(const char *path, int flags, mode_t mode);
originalOpen = reinterpret_cast<decltype(originalOpen)>(dlsym(RTLD_NEXT, "open"));
//originalOpen = reinterpret_cast<decltype(open)>(dlsym(RTLD_NEXT, "open"));
//...
return (*originalOpen)(path, flags, mode);
}
}
I compile with g++ -fPIC -shared -o open.so open.cpp -ldl.
Can somebody tell me why the above code works, and why I get the errror:
error: invalid cast from type ‘void*’ to type ‘int(const char*, int, mode_t)’ {aka ‘int(const char*, int, unsigned int)’}
originalOpen = reinterpret_cast<decltype(open)>(dlsym(RTLD_NEXT, "open"));
when I initialize originalOpen with the line commented out?
I used gcc version 8.0.1.
Try this code:
originalOpen = reinterpret_cast<decltype(open) *>(dlsym(RTLD_NEXT, "open"));
Decltype gets the type of the function while You want to create function pointer. There is implicit cast from function to pointer of its type but these are not equivalent. This is why version with decltype(original_open) works perfectly - type of original_open is function pointer and not the function.
I've built a VRPN client on Linux. It's based on this: http://www.vrgeeks.org/vrpn/tutorial---use-vrpn
Here's some of the code:
vrpn_Analog_Remote * analog = NULL;
vrpn_Button_Remote * button = NULL;
vrpn_Tracker_Remote * tracker = NULL;
// Things happen...
analog = new vrpn_Analog_Remote("pathToAnalog");
analog->register_change_handler(NULL, handleAnalog);
button = new vrpn_Button_Remote("pathToButton");
button->register_change_handler(NULL, handleButton);
tracker = new vrpn_Tracker_Remote("pathToTracker");
tracker->register_change_handler(NULL, handleTracker);
Here are the callbacks refered to in this code:
void handleAnalog(void * userData, const vrpn_ANALOGCB a) {
// Do stuff...
}
void handleButton(void * userData, const vrpn_BUTTONCB b) {
// Do stuff...
}
void handleTracker(void * userData, const vrpn_TRACKERCB t) {
// Do stuff...
}
And here is where all of these references to VRPN are defined:
https://github.com/vrpn/vrpn/blob/master/vrpn_Analog.h#L168
https://github.com/vrpn/vrpn/blob/master/vrpn_Button.h#L225
https://github.com/vrpn/vrpn/blob/master/vrpn_Tracker.h#L284
These compile without even a warning on Linux and can actually be used. Everything worked as expected. All the types here seem to satisfy the compiler, g++.
But on Windows, whether I use Visual Studio 2015 or MinGW's g++, I get this for the first two callback registrations:
invalid conversion from 'void (*)(void*, vrpn_ANALOGCB) {aka void (*)(void*, _vrpn_ANALOGCB)}' to 'vrpn_ANALOGCHANGEHANDLER {aka
void (__attribute__((__stdcall__)) *)(void*, _vrpn_ANALOGCB)}' [-fpermissive]
invalid conversion from 'void (*)(void*, vrpn_BUTTONCB) {aka void (*)(void*, _vrpn_BUTTONCB)}' to 'vrpn_BUTTONCHANGEHANDLER {aka
void (__attribute__((__stdcall__)) *)(void*, _vrpn_BUTTONCB)}' [-fpermissive]
And for the last one, I get a different error:
call of overloaded 'register_change_handler(NULL, void (&)(void*, vrpn_TRACKERCB))' is
ambiguous
Now that I'm typing this, I'm thinking maybe VRPN was compiled differently on Windows and that's why the compiler now has a problem with my code. But I'm very lost as to what to do.
Try declaring your callbacks like this:
void VRPN_CALLBACK handleAnalog(void * userData, const vrpn_ANALOGCB a) {
// Do stuff...
}
For linux, the VRPN_CALLBACK define is empty, so you did not notice any problems there. For windows, the VRPN library devs decided that they expect a callback that adheres to the __stdcall calling-convention. Thus you have to declare your function accordingly, and the most painless+portable way is to use the very same VRPN_CALLBACK define that they provide.
Clues to this came from your links to the code at github:
[vrpn_Analog.h]
typedef void(VRPN_CALLBACK *vrpn_ANALOGCHANGEHANDLER)(void *userdata,
const vrpn_ANALOGCB info);
and the callback define is made here:
[vrpn_Configure.h]
#ifdef _WIN32 // [ ...
#define VRPN_CALLBACK __stdcall
#else // ... ] WIN32 [
#define VRPN_CALLBACK
#endif // ] not WIN32
I found a library to handle joystick USB devices in C++ in
simple cross-platform gamepad library so I am trying to attach the callbacks from it to my application. So it has the following definitions
struct Gamepad_device {
unsigned int deviceID;
const char * description;
int vendorID;
int productID;
unsigned int numAxes;
unsigned int numButtons;
float * axisStates;
bool * buttonStates;
void * privateData;
};
[...]
/* Registers a function to be called whenever a device is attached. The specified
function will be called only during calls to Gamepad_init() and
Gamepad_detectDevices(), in the thread from which those functions were called.
Calling this function with a NULL argument will stop any previously registered
callback from being called subsequently. */
void Gamepad_deviceAttachFunc
(void (* callback)
(struct Gamepad_device * device, void * context), void * context);
Thus I am trying to attach this function Gamepad_deviceAttachFunc to a private function in my application.
I tried to register my private function joystickIsAttached (Gamepad_device device) using
Gamepad_deviceAttachFunc(joystickIsAttached(*Gamepad_device));
and
Gamepad_deviceAttachFunc(joystickIsAttached(*Gamepad_device));
but both lead me to
error: expected primary-expression before ')' token
Gamepad_deviceAttachFunc(joystickIsAttached(*Gamepad_device));
or
error: expected primary-expression before ')' token
Gamepad_deviceAttachFunc(joystickIsAttached(Gamepad_device));
Update
I also tried to define the called function as
void joystickDeviceAttachedCallback
(struct Gamepad_device * device, void * context);
and register the callback using
Gamepad_deviceAttachFunc(joystickDeviceAttachedCallback, (void *) 0x1);
but this leads to
error: cannot convert 'MainWindow::joystickDeviceAttachedCallback'
from type 'void (MainWindow::)(Gamepad_device*, void*)' to type 'void
()(Gamepad_device, void*)'
Gamepad_deviceAttachFunc(joystickDeviceAttachedCallback, (void *) 0x1);
Thus what did I do wrong (and how can I fix it?)?
Thanks.
Sorry if I'm not as descriptive as I should be, I'm nearly asleep as I type this. I am trying to create a posix thread in my c++ code compiling with g++ on mingw. Here's the except of the code I'm trying to compile
static void processNextNodeOnQueue(queue<TreeNode*> &toComputeQueue) {...}
void static processNodes(void* ptr) {
pair<queue<TreeNode*>*, bool*> *input = (pair<queue<TreeNode*>*, bool*>*) ptr;
while(*(input->second)) {
pthread_mutex_lock(&mutex1);
if(input->first->empty()) return;
pthread_mutex_unlock(&mutex1);
processNextNodeOnQueue(*(input->first));
}
}
void startThinking() {
thinking = true;
mutex1 = PTHREAD_MUTEX_INITIALIZER;
pthread_t thread;
pair<queue<TreeNode*>*, bool*> *input = new pair<queue<TreeNode*>*, bool*>(&toComputeQueue, &thinking);
int thereadId = pthread_create(&thread, NULL, (void*)&processNodes, (void*) input );
delete input;
}
void stopThinking() {
//set thinking to false and wait for threads to wrap up
thinking = false;
}
void processForTime(double seconds) {
clock_t t;
int f;
t = clock();
startThinking();
//something to wait for an amount of time
stopThinking();
}
Here's the full compiler output in case I missed something
C:\Users\Maxwell\SkyDrive\RPI\Fall 2013\IHSS-1964\Connect 4\MaxAI>g++ -g -pthread -std=c++11 -o3 *.cpp -o Max.exe
In file included from unit_tests.h:5:0,
from main.cpp:11:
search_tree.h: In member function 'void BoardSearchTree::startThinking()':
search_tree.h:221:85: error: invalid conversion from 'void*' to 'void* (__attribute__((__cdecl__)) *)(void*)' [-fpermissive]
int thereadId = pthread_create(&thread, NULL, (void*)&processNodes, (void*) input );
^
In file included from search_tree.h:12:0,
from unit_tests.h:5,
from main.cpp:11:
c:\mingw\include\pthread.h:940:31: error: initializing argument 3 of 'int pthread_create(pthread_t*, pthread_attr_t_*const*, void* (__attribute__((__cdecl__)) *)(void*), void*)' [-fpermissive] PTW32_DLLPORT int PTW32_CDECL pthread_create (pthread_t * tid,
The third parameter to pthread_create is a void *(*start_routine) (void *) - a function pointer. You are casting the function to a (void*) which is both unnecessary and incorrect. Just remove the cast:
pthread_create(&thread, NULL, processNodes, (void*) input );
Also since input is a pointer you don't need to cast it either, all pointers (save pointers-to-members) are implicitly convertible to void*):
pthread_create(&thread, NULL, processNodes, input );
Assuming you're using the pthread-w32 library from here, then the following header information is relevant:
#define PTW32_CDECL __cdecl
PTW32_DLLPORT int PTW32_CDECL pthread_create (pthread_t * tid,
const pthread_attr_t * attr,
void *(PTW32_CDECL *start) (void *),
void *arg);
What this shows is that the start parameter should be a function pointer that uses the __cdecl calling convention.
Try changing your processNodes function prototype to the following:
static void PTW32_CDECL processNodes(void* ptr)
The compiler should then create your thread function with the correct calling convention as expected by pthread_create.
I have made some helper functions for doing operations with CUDA __constant__ pointers (allocation, copyToSymbol, copyFromSymbol, etc). I also have error checking in place as suggested by talonmies here. Here is a basic working example:
#include <cstdio>
#include <cuda_runtime.h>
__constant__ float* d_A;
__host__ void cudaAssert(cudaError_t code,
char* file,
int line,
bool abort=true) {
if (code != cudaSuccess) {
fprintf(stderr, "CUDA Error: %s in %s at line %d\n",
cudaGetErrorString(code), file, line);
if (abort) {
exit(code);
}
}
}
#define cudaTry(ans) { cudaAssert((ans), __FILE__, __LINE__); }
template<typename T>
void allocateCudaConstant(T* &d_ptr,
size_t size) {
size_t memsize = size * sizeof(T);
void* ptr;
cudaTry(cudaMalloc((void**) &ptr, memsize));
cudaTry(cudaMemset(ptr, 0, memsize));
cudaTry(cudaMemcpyToSymbol(d_ptr, &ptr, sizeof(ptr),
0, cudaMemcpyHostToDevice));
}
int main() {
size_t size = 16;
allocateCudaConstant<float>(d_A, size);
return 0;
}
When I compile this with nvcc, I get the following warning:
In file included from tmpxft_0000a3e8_00000000-3_example.cudafe1.stub.c:2:
example.cu: In function ‘void allocateCudaConstant(T*&, size_t) [with T = float]’:
example.cu:35: instantiated from here
example.cu:29: warning: deprecated conversion from string constant to ‘char*’
I understand what the warning means, but I can't for the life of me figure out where it is coming from. If I don't make allocateCudaConstant a template function, I don't get the warning. If I don't wrap cudaMemcpyToSymbol in cudaTry, I also don't get the warning. I know it is just a warning, and if I compile with -Wno-write-strings I can suppress the warning. The code runs fine but I don't want to get in the habit of ignoring warnings and if I suppress the warnings, I may hide other issues that need to be addressed.
So, can anyone help me figure out where the warning is coming from and how I can suppress it?
Change char* file to const char* file in the declaration of cudaAssert. You don't need to modify the string, so you should not ask for a modifyable string.