Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to link non thread-safe library so each thread will have its own global variables from it?

I have a program that I link with many libraries. I run my application on profiler and found out that most of the time is spent in "waiting" state after some network requests. Those requests are effect of my code calling sleeping_function() from external library. I call this function in a loop which executes many, many times so all waiting times sum up to huge amounts.

As I cannot modify the sleeping_function() I want to start a few threads to run a few iterations of my loop in parallel. The problem is that this function internally uses some global variables.

Is there a way to tell linker on SunOS that I want to link specific libraries in a way that will place all variables from them in Thread Local Storage?

like image 654
elmo Avatar asked Nov 05 '22 08:11

elmo


1 Answers

I don’t think you’ll be able to achieve this with just the linker, but you might be able to get something working with some code in C.

The problem is that a call to load a library that is already loaded will return a reference to the already loaded instance instead of loading a new copy. A quick look at the documentation for dlopen and LoadLibrary seems to confirm that there’s no way to load the same library more than once, at least not if you want the image to be prepared for execution. One way to circumvent this would be to prevent the OS from knowing that it is the same library. To do this you could make a copy of the file.

Some pseudo code, just replace calls to sleeping_function with calls to call_sleeping_function_thread_safe:

char *shared_lib_name

void sleeping_function_thread_init(char *lib_name);

void call_sleeping_function_thread_safe()
{
  void *lib_handle;
  pthread_t pthread;
  new_file_name = make_copy_of_file(shared_lib_name);

  pthread_create(&pthread, NULL, sleeping_function_thread_init, new_file_name);
}

void sleeping_function_thread_init(char *lib_name)
{
  void *lib_handle;
  void (*)() sleeping_function;

  lib_handle = dlopen(lib_name, RTLD_LOCAL);
  sleeping_function = dlsym(lib_handle, "sleeping_function")
  while (...)
    sleeping_function;
  dlclose(lib_handle);
  delete_file(lib_name);      
}

For windows dlopen becomes LoadLibrary and dlsym becomes GetProcAddress etc... but the basic idea would still work.

like image 63
torak Avatar answered Nov 09 '22 11:11

torak