issues When curl_easy_perform run in thread return code 7 - libcurl

When curl_easy_perform run in thread return code 7 but not in main thread.
kernel 2.36.2 uClibc-0.9.33 libpthread.so-0.9.33.2
curl_east_perform work well in the below code:
int main(void) {
CURL * curl = curl_easy_inint;
curl_easy_setopt();
curl_east_perform(curl);
curl_easy_cleanup;
return 0;
}
curl_east_perform will always return 7 in the below code:
int main(void) {
curl_global_init(CURL_GLOBAL_ALL);
pthread_create(pid, NULL, curl_run_process, NULL);
return 0;
}
void *curl_run_process(void *arg) {
CURL *curl = curl_easy_init;
curl_easy_setopt();
curl_east_perform(curl);
curl_easy_cleanup;
}

Related

libcurl can't get CURLINFO_EFFECTIVE_URL

I use curl_easy_getinfo to get url, but sometimes it points to private memory, how can I solve it?
102 bool bb_curl::check_result(CURLcode code, CURL *handle, bool check_url) {
103 if (code == CURLE_OK) {
104 char *url = nullptr;
105 auto rc = curl_easy_getinfo(handle, CURLINFO_EFFECTIVE_URL, &url);
106 if (rc == CURLE_OK && url && check_url) {
107 int http_code;
108 curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE, &http_code);
109 if (http_code == 200)
110 BB_VERBOSE("[OK] %s\n", url);
111 else
112 BB_Warn("[ERROR] http code:%d, url: %s\n", http_code, url);
113 }
Use gdb:
Program received signal SIGSEGV, Segmentation fault.
(gdb) f 5
#5 0x00002aaaac7b79a3 in bb_curl::check_result (this=0x6572f0, code=CURLE_OK, handle=0x6f4ab0,
check_url=true) at /wsp/bb_curl.cpp:110
110 BB_VERBOSE("[OK] %s\n", url);
(gdb) p url
$1 = 0x2aaa00000000 <error: Cannot access memory at address 0x2aaa00000000>
I also set CURLOPT_FOLLOWLOCATION, 1,, can't fix it.
UPDATE
platform:
gcc (GCC) 4.9.3
curl 7.46.0 (x86_64-pc-linux-gnu) libcurl/7.46.0 OpenSSL/1.0.2e zlib/1.2.3 libidn/1.10 libssh2/0.19.0-20080814
SUSE Linux Enterprise Server 11 (x86_64)
I update the complete source code.
#include <curl/curl.h>
#include <cstdlib>
#include <string>
#include <vector>
#include <future>
/* reserved vector */
template <class T>
inline std::vector<T> bb_reserved_vector(size_t n) {
std::vector<T> vec;
vec.reserve(n);
return vec;
}
size_t write_cb(char *ptr, size_t size, size_t nmemb, void *userdata) {
return size * nmemb;
}
bool check_result(CURLcode code, CURL *handle, bool check_url) {
if (code == CURLE_OK && handle != nullptr) {
char *url = nullptr;
auto rc = curl_easy_getinfo(handle, CURLINFO_EFFECTIVE_URL, &url);
if (rc == CURLE_OK && url && check_url) {
int http_code;
curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE, &http_code);
if (http_code == 200)
printf("[OK] %s\n", url);
else
printf("[ERROR] http code:%d, url: %s\n", http_code, url);
}
return true;
} else {
printf("[ERROR] curl code %d\n", code);
return false;
}
}
int main() {
size_t sz = 1000;
auto futures = bb_reserved_vector<std::future<CURLcode>>(sz);
auto handles = bb_reserved_vector<CURL *>(sz);
auto results = std::vector<std::string>(sz);
curl_global_init(CURL_GLOBAL_ALL);
for (size_t i = 0; i < sz; ++i) {
handles.push_back(curl_easy_init());
int curl_code = curl_easy_setopt(handles[i], CURLOPT_WRITEDATA, (void *) &results[i]);
curl_code += curl_easy_setopt(handles[i], CURLOPT_URL, "www.example.com");
curl_code += curl_easy_setopt(handles[i], CURLOPT_WRITEFUNCTION, write_cb);
curl_code += curl_easy_setopt(handles[i], CURLOPT_FOLLOWLOCATION, 1);
curl_code += curl_easy_setopt(handles[i], CURLOPT_NOSIGNAL, 1);
if (curl_code != 0)
printf("Set option error\n");
auto fut = std::async(std::launch::async, curl_easy_perform, handles[i]);
futures.push_back(std::move(fut));
}
// synchronize
for (size_t i = 0; i < futures.size(); ++i) {
futures[i].wait();
check_result(futures[i].get(), handles[i], true);
}
// cleanup
for (auto &item : handles)
curl_easy_cleanup(item);
curl_global_cleanup();
return 0;
}
It seems you made a small but fatal error. The type of http_code should be long instead of int. Apparently, the call to curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE, &http_code) overwrote the memory used by url on CentOS. Making this change fixed the crash on CentOS for me. Please be aware that long on 64-bit Linux is 8 bytes, longer than int.
Probably the bug is not in the code you posted. It might be that you sometimes pass an invalid CURL* handle.
I checked this and indeed, if you pass an invalid handle, the function curl_easy_getinfo still returns CURLE_OK. A segmentation fault occurs later if you try to access the char* url variable. The propgram (compile with g++ main.cpp -lcurl)
#include <iostream>
#include <curl/curl.h>
using namespace std;
int main(void){
char* url;
CURL *handle;
handle=curl_easy_init();
curl_easy_setopt(handle, CURLOPT_URL, "http://www.example.com");
CURL *bug=(CURL*)((long)(handle)+1);
CURLcode code= curl_easy_getinfo(bug, CURLINFO_EFFECTIVE_URL, &url);
cout<<"CURLE_OK="<<CURLE_OK<< " and code="<<code<<endl;
cout <<"URL: "<<url; //This line causes segmentation fault;
curl_easy_cleanup(handle);
return EXIT_SUCCESS;
}
produces something like:
CURLE_OK=0 and code=0
Program received signal SIGSEGV, Segmentation fault.

Trying to call a certain function each time

Okay, so I've an assignment with threads.I'm suppose to change the current running threads each period of time, let's say a second. First of all I've created a Thread class:
typedef unsigned long address_t;
#define JB_SP 6
#define JB_PC 7
#define STACK_SIZE (4096)
using namespace std;
class Thread{
public:
enum State{
BLOCKED,
READY,
RUNNING
};
Thread(int tid, void(*f)(void), int stack_size) :
tid(tid), stack_size(stack_size){
address_t sp, pc;
sp = (address_t)stack + STACK_SIZE - sizeof(address_t);
pc = (address_t)f;
sigsetjmp(env, 1);
(env->__jmpbuf)[JB_SP] = translate_address(sp);
(env->__jmpbuf)[JB_PC] = translate_address(pc);
sigemptyset(&env->__saved_mask);
state = READY;
quantums = 0;
}
Thread (){}
address_t translate_address(address_t addr)
{
address_t ret;
asm volatile("xor %%fs:0x30,%0\n"
"rol $0x11,%0\n"
: "=g" (ret)
: "0" (addr));
return ret;
}
State get_state() const
{
return state;
}
void set_state(State state1)
{
state = state1;
}
int get_id() const
{
return tid;
}
pthread_t& get_thread()
{
return thread;
}
sigjmp_buf& get_env()
{
return env;
}
void raise_quantums()
{
quantums ++;
}
int get_quantums()
{
return quantums;
}
int add_to_sync(int tid)
{
sync.push_back(tid);
}
bool appear_in_sync_list(int tid)
{
return (find(sync.begin(), sync.end(), tid) != sync.end());
}
private:
vector<int> sync;
int quantums;
State state;
char stack[STACK_SIZE];
sigjmp_buf env;
pthread_t thread;
int tid;
int stack_size;
};
I've this function which changes threads:
void running_thread(int sigNum)
{
sigset_t set;
sigemptyset(&set);
sigaddset(&set, SIGINT);
sigprocmask(SIG_SETMASK, &set, NULL);
total_quantum ++;
if (currentThread.get_state() == Thread::RUNNING)
{
Thread& t = ready_threads.back();
ready_threads.pop_back();
currentThread.set_state(Thread::READY);
ready_threads.push_back(currentThread);
sigsetjmp(currentThread.get_env(), 1);
currentThread = t;
t.raise_quantums();
siglongjmp(currentThread.get_env(), 1);
}
if (currentThread.get_state() == Thread::BLOCKED)
{
Thread &t = ready_threads.back();
ready_threads.pop_back();
currentThread.set_state(Thread::BLOCKED);
blocked_threads.push_back(currentThread);
sigsetjmp(currentThread.get_env(), 1);
currentThread = t;
t.raise_quantums();
siglongjmp(currentThread.get_env(), 1);
}
sigemptyset(&set);
sigaddset(&set, SIGINT);
sigprocmask(SIG_UNBLOCK, &set, NULL);
}
It actually doesn't matter what it do, my problem is that it isn't even called.
My program first call this function:
int clock_set()
{
int seconds = quantum / SECOND;
int usecs = quantum - seconds*SECOND;
timer.it_value.tv_sec = seconds;
timer.it_value.tv_usec = usecs;
timer.it_interval.tv_sec = seconds;
timer.it_interval.tv_usec = usecs;
struct sigaction sa;
sa.sa_handler = &running_thread;
if (sigaction(SIGVTALRM, &sa,NULL) < 0) {
cerr << "system error: sigaction error.";
return FAILURE;
}
// Start a virtual timer. It counts down whenever this process is executing.
if (setitimer (ITIMER_VIRTUAL, &timer, NULL)) {
cerr << "system error: setitimer error.";
return FAILURE;
}
return SUCCESS;
}
Basically I was trying to make running_thread get activate each second, so I Was using sigaction and sa_handler.
This is my main function:
int main()
{
uthread_init(1000000) // Initiliaze variable 'quantum' to be a second, this function also calls clock_set
uthread_spawn(&g); // Creating a thread object with function g inserting it to ready_threads vector and to threads vector
uthread_spawn(&f); // creating a thread object with function f inserting it to ready_threads vector and to threads vector
}
The vector "ready_threads" has 2 threads in it.
Why doesn't it call running_thread?

Pthreads pool, keeping 1000 opened threads, pthread_create() returns 11

Need some help with PTHREADS. I want to keep over 1000 threads opened at any time, something like a thread pool. Here is the code :
/*
gcc -o test2 test2.cpp -static -lpthread -lstdc++
*/
#include <iostream>
#include <cstdlib>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <cstring>
#include <stdexcept>
#include <cstdlib>
int NUM_THREADS = 2000;
int MAX_THREADS = 100;
int THREADSTACK = 65536;
struct thread_struct{
int arg1;
int arg2;
};
pthread_mutex_t mutex_;
static unsigned int thread_count = 0;
string exec(const char* cmd)
{
int DEBUG=0;
char buffer[5000];
string result = "";
FILE* pipe = popen(cmd, "r");
if (!pipe && DEBUG) throw runtime_error("popen() failed!");
try
{
while (!feof(pipe))
{
if (fgets(buffer, 128, pipe) != NULL)
{
result += buffer;
}
}
}
catch(...)
{
pclose(pipe);
throw;
}
pclose(pipe);
return result;
}
void *thread_test(void *arguments)
{
pthread_mutex_lock(&mutex_);
thread_count++;
pthread_mutex_unlock(&mutex_);
// long tid;
// tid = (long)threadid;
struct thread_struct *args = (thread_struct*)arguments;
/*
printf("ARG1=%d\n",args->arg1);
printf("ARG2=%d\n",args->arg2);
*/
int thread_id = (int) args->arg1;
/*
int random_sleep;
random_sleep = rand() % 10 + 1;
printf ("RAND=[%d]\n", random_sleep);
sleep(random_sleep);
*/
int random_sleep;
random_sleep = rand() % 10 + 5;
// printf ("RAND=[%d]\n", random_sleep);
char command[100];
memset(command,0,sizeof(command));
sprintf(command,"sleep %d",random_sleep);
exec(command);
random_sleep = rand() % 100000 + 500000;
usleep(random_sleep);
// simulation of a work between 5 and 10 seconds
// sleep(random_sleep);
// printf("#%d -> sleep=%d total_threads=%u\n",thread_id,random_sleep,thread_count);
pthread_mutex_lock(&mutex_);
thread_count--;
pthread_mutex_unlock(&mutex_);
pthread_exit(NULL);
}
int main()
{
// pthread_t threads[NUM_THREADS];
int rc;
int i;
usleep(10000);
srand ((unsigned)time(NULL));
unsigned int thread_count_now = 0;
pthread_attr_t attrs;
pthread_attr_init(&attrs);
pthread_attr_setstacksize(&attrs, THREADSTACK);
pthread_mutex_init(&mutex_, NULL);
for( i=0; i < NUM_THREADS; i++ )
{
create_thread:
pthread_mutex_lock(&mutex_);
thread_count_now = thread_count;
pthread_mutex_unlock(&mutex_);
// printf("thread_count in for = [%d]\n",thread_count_now);
if(thread_count_now < MAX_THREADS)
{
printf("CREATE thread [%d]\n",i);
struct thread_struct struct1;
struct1.arg1 = i;
struct1.arg2 = 999;
pthread_t temp_thread;
rc = pthread_create(&temp_thread, NULL, &thread_test, (void *)&struct1);
if (rc)
{
printf("Unable to create thread %d\n",rc);
sleep(1);
pthread_detach(temp_thread);
goto create_thread;
}
}
else
{
printf("Thread POOL full %d of %d\n",thread_count_now,MAX_THREADS);
sleep(1);
goto create_thread;
}
}
pthread_attr_destroy(&attrs);
pthread_mutex_destroy(&mutex_);
// pthread_attr_destroy(&attrs);
printf("Proccess completed!\n");
pthread_exit(NULL);
return 1;
}
After spawning 300 threads it begins to give
errors, return code from pthread_create() is 11, and after that keeps executing them one by one.
What im i doing wrong?
According to this website, error code 11 corresponds to EAGAIN which means according to this:
Insufficient resources to create another thread.
A system-imposed limit on the number of threads was encountered.
Hence to solve your problem either create less threads or wait for running ones to finish before creating new ones.
You can also change default thread stack size see pthread_attr_setstacksize

Why does FUSE seem to be locking up all threads?

I took fuse hello.c and modified the bottom to show what I am talking about. In my app I need to do things after my fuse FS is available. I also need another thread for IPC and keeping certain things up to date. Because fuse_main doesn't appear to return I threw it in its own thread.
When I comment out fuse_main the console shows A and B printed. However if I don't comment out fuse_main (which is in a different thread) only A is printed. How the heck is fuse stopping my main thread and how do I run code after FUSE does its thing?
#define FUSE_USE_VERSION 26
#include <fuse.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
static const char *hello_str = "Hello World!\n";
static const char *hello_path = "/hello";
static int hello_getattr(const char *path, struct stat *stbuf)
{
int res = 0;
memset(stbuf, 0, sizeof(struct stat));
if (strcmp(path, "/") == 0) {
stbuf->st_mode = S_IFDIR | 0755;
stbuf->st_nlink = 2;
} else if (strcmp(path, hello_path) == 0) {
stbuf->st_mode = S_IFREG | 0444;
stbuf->st_nlink = 1;
stbuf->st_size = strlen(hello_str);
} else
res = -ENOENT;
return res;
}
static int hello_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
off_t offset, struct fuse_file_info *fi)
{
(void) offset;
(void) fi;
if (strcmp(path, "/") != 0)
return -ENOENT;
filler(buf, ".", NULL, 0);
filler(buf, "..", NULL, 0);
filler(buf, hello_path + 1, NULL, 0);
return 0;
}
static int hello_open(const char *path, struct fuse_file_info *fi)
{
if (strcmp(path, hello_path) != 0)
return -ENOENT;
if ((fi->flags & 3) != O_RDONLY)
return -EACCES;
return 0;
}
static int hello_read(const char *path, char *buf, size_t size, off_t offset,
struct fuse_file_info *fi)
{
size_t len;
(void) fi;
if(strcmp(path, hello_path) != 0)
return -ENOENT;
len = strlen(hello_str);
if (offset < len) {
if (offset + size > len)
size = len - offset;
memcpy(buf, hello_str + offset, size);
} else
size = 0;
return size;
}
static struct fuse_operations hello_oper;
//modification starts below this line
#include<thread>
#include<unistd.h>
int main(int argc, char *argv[])
{
std::thread t([&]{
hello_oper.getattr = hello_getattr;
hello_oper.readdir = hello_readdir;
hello_oper.open = hello_open;
hello_oper.read = hello_read;
return fuse_main(argc, argv, &hello_oper, NULL);
});
printf("A\n");
sleep(5);
printf("B\n");
t.join();
}
fuse_main daemonizes, i.e. calls fork() and calls _exit(0) in the parent process, so the process exits, hence you only see the A printout.
If you give the option -f in ./hello -f /tmp/fuse the fuse_main does not call _exit but stays alive in the foreground and both A and B can be seen.
You surely need a way to end the fuse_main thread gracefully when your program wants to exit:
//modification starts below this line
#include<thread>
#include<unistd.h>
#include <signal.h>
#include <sys/syscall.h>
int main(int argc, char *argv[])
{
pid_t tid;
std::thread t([&]{
hello_oper.getattr = hello_getattr;
hello_oper.readdir = hello_readdir;
hello_oper.open = hello_open;
hello_oper.read = hello_read;
tid = syscall(SYS_gettid);
return fuse_main(argc, argv, &hello_oper, NULL);
});
printf("A\n");
sleep(5);
printf("B\n");
kill(tid, SIGTERM);
t.join();
}
Options for hello:
general options:
-o opt,[opt...] mount options
-h --help print help
-V --version print version
FUSE options:
-d -o debug enable debug output (implies -f)
-f foreground operation
-s disable multi-threaded operation
[...]
From what I read in the documentation here http://fuse.sourceforge.net/doxygen/hello_8c.html on the usage of the hello.c program, it says that the program exits and vanishes into the background, that is the nature of the fuse_main API . Why don't you give a try, starting with this code
http://fuse.sourceforge.net/doxygen/hello__ll_8c.html, from their description,
unlike hello.c this example will stay in the foreground. it also replaced the convenience function fuse_main(..) with a more low level approach. This way in the line,
err = fuse_session_loop(se);
in the main function you have control to have additions and do other things you wish to do.
Also there is a c++ implementation for FUSE, https://code.google.com/p/fusekit/
Hope this helps.

Embedding matplotlib in C++

I am reading a message from a socket with C++ code and am trying to plot it interactively with matplotlib, but it seems Python code will block the main thread, no matter I use show() or ion() and draw(). ion() and draw() won't block in Python.
Any idea how to plot interactively with matplotlib in C++ code?
An example would be really good.
Thanks a lot.
You may also try creating a new thread that does the call to the
blocking function, so that it does not block IO in your main program
loop. Use an array of thread objects and loop through to find an unused
one, create a thread to do the blocking calls, and have another thread
that joins them when they are completed.
This code is a quick slap-together I did to demonstrate what I mean about
using threads to get pseudo asynchronous behavior for blocking functions...
I have not compiled it or combed over it very well, it is simply to show
you how to accomplish this.
#include <pthread.h>
#include <sys/types.h>
#include <string>
#include <memory.h>
#include <malloc.h>
#define MAX_THREADS 256 // Make this as low as possible!
using namespace std;
pthread_t PTHREAD_NULL;
typedef string someTypeOrStruct;
class MyClass
{
typedef struct
{
int id;
MyClass *obj;
someTypeOrStruct input;
} thread_data;
void draw(); //Undefined in this example
bool getInput(someTypeOrStruct *); //Undefined in this example
int AsyncDraw(MyClass * obj, someTypeOrStruct &input);
static void * Joiner(MyClass * obj);
static void * DoDraw(thread_data *arg);
pthread_t thread[MAX_THREADS], JoinThread;
bool threadRunning[MAX_THREADS], StopJoinThread;
bool exitRequested;
public:
void Main();
};
bool MyClass::getInput(someTypeOrStruct *input)
{
}
void MyClass::Main()
{
exitRequested = false;
pthread_create( &JoinThread, NULL, (void *(*)(void *))MyClass::Joiner, this);
while(!exitRequested)
{
someTypeOrStruct tmpinput;
if(getInput(&tmpinput))
AsyncDraw(this, tmpinput);
}
if(JoinThread != PTHREAD_NULL)
{
StopJoinThread = true;
pthread_join(JoinThread, NULL);
}
}
void *MyClass::DoDraw(thread_data *arg)
{
if(arg == NULL) return NULL;
thread_data *data = (thread_data *) arg;
data->obj->threadRunning[data->id] = true;
// -> Do your draw here <- //
free(arg);
data->obj->threadRunning[data->id] = false; // Let the joinThread know we are done with this handle...
}
int MyClass::AsyncDraw(MyClass *obj, someTypeOrStruct &input)
{
int timeout = 10; // Adjust higher to make it try harder...
while(timeout)
{
for(int i = 0; i < MAX_THREADS; i++)
{
if(thread[i] == PTHREAD_NULL)
{
thread_data *data = (thread_data *)malloc(sizeof(thread_data));
if(data)
{
data->id = i;
data->obj = this;
data->input = input;
pthread_create( &(thread[i]), NULL,(void* (*)(void*))MyClass::DoDraw, (void *)&data);
return 1;
}
return 0;
}
}
timeout--;
}
}
void *MyClass::Joiner(MyClass * obj)
{
obj->StopJoinThread = false;
while(!obj->StopJoinThread)
{
for(int i = 0; i < MAX_THREADS; i++)
if(!obj->threadRunning[i] && obj->thread[i] != PTHREAD_NULL)
{
pthread_join(obj->thread[i], NULL);
obj->thread[i] = PTHREAD_NULL;
}
}
}
int main(int argc, char **argv)
{
MyClass base;
base.Main();
return 0;
}
This way you can continue accepting input while the draw is occurring.
~~Fixed so the above code actually compiles, make sure to add -lpthread