Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

Commit

Permalink
Merge pull request #85 from mapbox/threaded-curl
Browse files Browse the repository at this point in the history
add threading for libcurl
  • Loading branch information
kkaefer committed Mar 3, 2014
2 parents a31fab1 + 45385d1 commit dadc8f1
Show file tree
Hide file tree
Showing 11 changed files with 365 additions and 79 deletions.
6 changes: 6 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ linux: config.gypi src linux/llmr-app.gyp
make -C build/linux-make V=$(V)
./build/linux-make/out/Release/llmr.app


# build OS X app with Xcode
lproj: config.gypi src linux/llmr-app.gyp
deps/run_gyp linux/llmr-app.gyp -Goutput_dir=./out/ --depth=. --generator-output=./ -f xcode
open ./linux/llmr-app.xcodeproj

# build just xcode project for libllmr
xcode: config.gypi llmr.gyp
deps/run_gyp llmr.gyp -Goutput_dir=./out/ --depth=. --generator-output=./ -f xcode
Expand Down
2 changes: 1 addition & 1 deletion include/llmr/map/tile.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ class Tile : public std::enable_shared_from_this<Tile>,
// Source data
std::string data;
const Style& style;
platform::Request req;
platform::Request *req = nullptr;
};

}
Expand Down
9 changes: 3 additions & 6 deletions include/llmr/platform/platform.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,18 @@ namespace platform {
// Restarts painting. This could for example trigger the event loop of the controlling application.
void restart();

struct Request {
int16_t identifier = -1;
std::string original_url;
};
class Request;

struct Response {
int16_t code = -1;
std::string body;
};

// Makes an HTTP request of a URL on a background thread, calls a function with the results on the same thread, and finally calls a callback function on the main thread. Returns a cancellable request.
Request request_http(std::string url, std::function<void(Response&)> background_function, std::function<void()> foreground_callback);
Request *request_http(std::string url, std::function<void(Response&)> background_function, std::function<void()> foreground_callback);

// Cancels an HTTP request.
void cancel_request_http(Request request);
void cancel_request_http(Request *request);

// Returns a relative timestamp in seconds. This value must be monotonic.
double time();
Expand Down
45 changes: 45 additions & 0 deletions include/llmr/util/threadpool.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#ifndef LLMR_UTIL_THREADPOOL
#define LLMR_UTIL_THREADPOOL

#include <pthread.h>
#include <forward_list>
#include <queue>

namespace llmr {
namespace util {

class Threadpool {
private:
class Worker {
public:
Worker(Threadpool& pool);
~Worker();
static void *loop(void *ptr);

private:
Threadpool& pool;
pthread_t thread;
};

public:
Threadpool(int max_workers = 4);
typedef void (*Callback)(void *);
void add(Callback callback, void *data);

private:
typedef std::pair<Callback, void *> Task;
const int max_workers;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t condition = PTHREAD_COND_INITIALIZER;
std::forward_list<Worker> workers;
int worker_count = 0;
std::queue<Task> tasks;
};

extern std::unique_ptr<Threadpool> threadpool;

}
}

#endif

61 changes: 50 additions & 11 deletions linux/llmr-app.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,57 @@
"sources": [
"./main.cpp",
"./settings.cpp",
"./settings.hpp"
"./settings.hpp",
"./request.cpp",
"./request.hpp"
],
'product_extension': 'app',
'link_settings': {
'libraries': [
'<@(glfw3_libraries)',
'-lcurl'
],
},
'cflags': [
'<@(png_cflags)',
'<@(glfw3_cflags)'
'conditions': [
['OS == "mac"', {
'product_extension': 'app',
'mac_bundle': 1,
'mac_bundle_resources': [
'../macosx/Icon.icns',
],
'link_settings': {
'libraries': [
'$(SDKROOT)/System/Library/Frameworks/Cocoa.framework',
'$(SDKROOT)/System/Library/Frameworks/IOKit.framework',
'$(SDKROOT)/System/Library/Frameworks/OpenGL.framework',
'$(SDKROOT)/System/Library/Frameworks/CoreVideo.framework',
],
},
'xcode_settings': {
'ARCHS': [ "x86_64" ],
'SDKROOT': 'macosx',
'SUPPORTED_PLATFORMS':'macosx',
'OTHER_CPLUSPLUSFLAGS':[
'<@(glfw3_cflags)'
],
'OTHER_LDFLAGS': [
'-stdlib=libc++',
'<@(glfw3_libraries)',
'-lcurl',
],
'SDKROOT': 'macosx',
'INFOPLIST_FILE': '../macosx/Info.plist',
'CLANG_CXX_LIBRARY': 'libc++',
'CLANG_CXX_LANGUAGE_STANDARD':'c++11',
'MACOSX_DEPLOYMENT_TARGET':'10.9',
'GCC_VERSION': 'com.apple.compilers.llvm.clang.1_0',
'CLANG_ENABLE_OBJC_ARC': 'YES'
},
}, {
'link_settings': {
'libraries': [
'<@(glfw3_libraries)',
'-lcurl'
],
},
'cflags': [
'<@(png_cflags)',
'<@(glfw3_cflags)'
],
}]
],
"dependencies": [
"../llmr.gyp:llmr-x86"
Expand Down
93 changes: 39 additions & 54 deletions linux/main.cpp
Original file line number Diff line number Diff line change
@@ -1,19 +1,13 @@
#include <llmr/llmr.hpp>
#include <GLFW/glfw3.h>
#include <curl/curl.h>
#include <llmr/platform/platform.hpp>
#include "settings.hpp"
#include <future>
#include <list>
#include <chrono>

#include <thread>
#include "settings.hpp"
#include "request.hpp"

std::list<std::future<void>> futures;
std::list<std::future<void>>::iterator f_it;
std::list<std::function<void()>> callbacks;
std::list<std::function<void()>>::iterator c_it;
std::chrono::milliseconds zero (0);
std::forward_list<llmr::platform::Request *> requests;

class MapView {
public:
Expand Down Expand Up @@ -45,8 +39,13 @@ class MapView {
glfwSetWindowUserPointer(window, this);
glfwMakeContextCurrent(window);

int width, height;
glfwGetWindowSize(window, &width, &height);
int fb_width, fb_height;
glfwGetFramebufferSize(window, &fb_width, &fb_height);

settings.load();
map.setup();
map.setup((double)fb_width / width);

resize(window, 0, 0);

Expand Down Expand Up @@ -159,21 +158,17 @@ class MapView {

int run() {
while (!glfwWindowShouldClose(window)) {

f_it = futures.begin();
c_it = callbacks.begin();

while (f_it != futures.end()) {
if (f_it->wait_for(zero) == std::future_status::ready) {
std::function<void()> cb = *c_it;
futures.erase(f_it++);
callbacks.erase(c_it++);
cb();
bool& dirty = this->dirty;
requests.remove_if([&dirty](llmr::platform::Request * req) {
if (req->done) {
req->foreground_callback();
delete req;
dirty = true;
return true;
} else {
f_it++;
c_it++;
return false;
}
}
});

if (dirty) {
try {
Expand All @@ -185,7 +180,7 @@ class MapView {
fps();
}

if (dirty || futures.size()) {
if (!requests.empty() || dirty) {
glfwPollEvents();
} else {
glfwWaitEvents();
Expand Down Expand Up @@ -237,58 +232,48 @@ MapView *mapView = nullptr;
namespace llmr {
namespace platform {

void restart(void *) {
void restart() {
if (mapView) {
mapView->dirty = true;
}
}



static size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp) {
((std::string*)userp)->append((char*)contents, size *nmemb);
return size * nmemb;
Request *request_http(std::string url, std::function<void(Response&)> background_function, std::function<void()> foreground_callback) {
Request *req = new Request(url, background_function, foreground_callback);
requests.push_front(req);
return req;
}

void request_http_async(std::string url, std::function<void(Response&)> func) {

Response res;

CURL *curl;
CURLcode code;
curl = curl_easy_init();

if (curl) {
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &res.body);
curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, "deflate");
code = curl_easy_perform(curl);
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &res.code);
curl_easy_cleanup(curl);
void cancel_request_http(Request *request) {
for (Request *req : requests) {
if (req == request) {
req->cancel();
}
}

func(res);
}

void request_http(std::string url, std::function<void(Response&)> func, std::function<void()> cb) {
futures.emplace_back(std::async(std::launch::async, request_http_async, url, func));
callbacks.push_back(cb);
}


double time() {
return glfwGetTime();
}

}
}


int main() {
curl_global_init(CURL_GLOBAL_ALL);

llmr::platform::Request::initialize();

mapView = new MapView();
mapView->init();
int ret = mapView->run();
mapView->settings.sync();
delete mapView;


llmr::platform::Request::finish();

curl_global_cleanup();
return ret;
}
Loading

0 comments on commit dadc8f1

Please sign in to comment.