What is the best of passing taskHandle to another class in freeRTOS with pointers - c++

OK it was not wise to ask question with some assumptions. Here is the detailed version.
I have 2 task, 1 for MQTT and 1 for LED. I want to read a data over MQTT and take an action to turn on an LED.
Here is my task declarations:
void taskMqtt(void *param);
xTaskHandle handleTaskMqtt;
void taskLed(void *param);
xTaskHandle handleTaskLed;
Here is the task creation part
status = xTaskCreate(taskMqtt, "taskMqtt", 4096, NULL, 2, handleTaskMqtt);
configASSERT(status == pdPASS);
ESP_LOGI(TAG, "taskMqtt CREATED");
status = xTaskCreate(taskLed, "taskLed", 4096, NULL, 2, &handleTaskLed);
configASSERT(status == pdPASS);
ESP_LOGI(TAG, "taskLed CREATED");
I created my Mqtt object like this and it works fine.
Mqtt mqtt("192.168.137.212", move(uptrWifi), handleTaskLed);
Here is the Mqtt.h file to observe class declaration
class Mqtt
{
private:
std::unique_ptr<Wifi> uptrWifi;
static xTaskHandle handlerTask;
static const char *subscribeTopic;
static const char *publishTopic;
static esp_mqtt_client_config_t _mqttCfg;
static esp_mqtt_client_handle_t _clientCfg;
static void mqttEventHandler(void *arg, esp_event_base_t eventBase, int32_t eventId, void *eventData);
public:
Mqtt(const char *brokerIp, std::unique_ptr<Wifi> uptrToWifi, xTaskHandle taskToNotify);
void init(void);
void sendDataOverMqtt(std::string title, int data);
void sendDataOverMqtt(std::string title, int data, std::string pubTopic);
static void getDataOverMqtt(char *data, int dataLen);
void setTopics(std::string subTopic, std::string pubTopic);
};
In Mqtt.cpp file I defined
xTaskHandle Mqtt::handlerTask;
and constructor
Mqtt::Mqtt(const char *brokerIp, std::unique_ptr<Wifi> uptrToWifi,
xTaskHandle taskToNotify)
{
_mqttCfg.host = brokerIp;
ESP_LOGI("MQTT_H", "MQTT BROKER IP SET\n");
uptrWifi = move(uptrToWifi);
handlerTask = taskToNotify;
}
and here is my function for read data and forward to the LED task.
void Mqtt::getDataOverMqtt(char *data, int dataLen)
{
static uint32_t valueToSend = 1;
if (strncmp(data, "Led ON", 6) == 0)
{
ESP_LOGI(TAG, "\nDATA COMES \n");
if (handlerTask != NULL)
{
xTaskNotify(handlerTask, valueToSend, eSetValueWithOverwrite);
}
else
{
printf("\nNULL pointer\n");
fflush(stdout);
}
printf("\nCMD=%.*s\n\n", dataLen, data);
}
else if (strncmp(data, "Led OFF", 7) == 0)
{
printf("\nCMD=%.*s\n\n", dataLen, data);
}
}
And here is the LED task
void taskLed(void *param)
{
uint32_t ulNotifiedValue = false;
while (1)
{
ESP_LOGI(TAG, "LED WAITING");
xTaskNotifyWait(0, ULONG_MAX, &ulNotifiedValue, portMAX_DELAY);
ESP_LOGI(TAG, "\n NOTIFICATION \n");
ESP_LOGI(TAG, "LED TASK RUNNING");
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
When I run the code and sent Led ON command, I can see the logs
LED WAITING (from taskLED definition)
DATA COMES (from getDataOverMqtt definition)
Null Pointer (from getDataOverMqtt definition)
After that I was hoping to see on the logs
NOTIFICATION (from taskLED defition)
////////////////////////////////////// ORIGINAL POST BEFORE EDITS IS BELOW
I am trying to learn FreeRtos and C++.
I need to pass taskHandle to another class and want to use them for notify function. What is the best way to do that?
In taskControl.cpp file I created tasks as below.
void task1(void *param);
TaskHandle_t handleTask1;
void task2(void *param);
TaskHandle_t handleTask2;
status = xTaskCreate(task1, "task1", 4096, NULL, 2, &handleTask1);
configASSERT(status == pdPASS);
ESP_LOGI(TAG, "task1 CREATED");
status = xTaskCreate(task2, "task2", 4096, NULL, 2, &handleTask2);
configASSERT(status == pdPASS);
ESP_LOGI(TAG, "task2 CREATED");
I thought I can pass handleTask2 into another class via constructor
M m(&handleTask2);
In classM.h file, M is declared as below
class M
{
private:
static TaskHandle_t *handlerTask;
public:
M(TaskHandle_t *taskToNotify)
{
handlerTask = taskToNotify;
}
};
And I tried to use handlerTask as below in classM.cpp file.
xTaskNotify(&handlerTask, valueToSend, eSetValueWithoutOverwrite);
What am I missing? What is the correct way to do this kind of thing?
Sorry for if my question is not clear.

Related

How to pass a member function pointer to libusb?

I'm writing a simple library that uses libusb to connect to my custom hardware that sends signals to a host device every 50ms. It's designed to provide a simple abstraction layer so that users are not bothered with libusb at all. I need to pass a pointer to a non-static class member function to libusb_fill_bulk_transfer. I.e. I need to have a separate callback for every instance of MyDevice without exposing libusb logic to my users.
The basic design is:
init the lib
int mylib_init(){
libusb_init(&context);
}
find all compatible devices
int mylib_get_valid_devices(vector devs){
//...
libusb_device **devs1;
int countAll = libusb_get_device_list(context, &devs1);
//... fill devs
}
int mylib_print_device_info(MyDevice* dev);
connect to as many devices as the user likes
int mylib_init_device(MyDevice* dev){
libusb_open(dev->device, &dev->dev_handle);
// check for kernel driver & remove if needed
libusb_claim_interface(dev->dev_handle, 0);
//...
}
set up callbacks for incoming data to all instances of connected devices
int mylib_start_transmission_async(MyDevice* dev, MyLibCallbackIn user_cb, unsigned char* buffer_in, int bufferSize){
libusb_control_transfer(dev->dev_handle, p1, p2, p3, p4, p5, p6, p7);
// .. rest of libusb_control_transfer -s
//start device:
int actual;
unsigned char startSig = 0b00110111;
libusb_bulk_transfer(dev->dev_handle, (1 | LIBUSB_ENDPOINT_OUT), &tosend, 1, &actual, 100);
dev->user_callback = user_cb;
dev->buffer_in = buffer_in;
dev->bufferSize = bufferSize;
//setup transfer
dev->transfer_in = libusb_alloc_transfer(0);
libusb_fill_bulk_transfer(dev->transfer_in, dev->dev_handle, LIBUSB_ENDPOINT_IN, dev->buffer_in,dev->bufferSize, cb_in, NULL, 0);
libusb_submit_transfer(dev->transfer_in);
}
disconnect when finished
int mylib_disconnect_device(MyDevice* device);
exit the lib
int mylib_exit();
MyDevice is defined as:
typedef int (*MyLibdCallbackIn)(unsigned char* buffer, int length);
class MyDevice{
unsigned char* buffer_in;
unsigned char* buffer_out;
libusb_device* device = nullptr;
libusb_device_handle* dev_handle = nullptr;
struct libusb_transfer* transfer_in = nullptr;
struct libusb_transfer* transfer_out = nullptr;
//this obviously wouldn't work because libusb doesn't accept it as a param:
void LIBUSB_CALL cb_in(struct libusb_transfer* transfer);
MyLibCallbackIn user_callback;
void run();
//...
}
and cb_in is defined as:
void LIBUSB_CALL MyDevice::cb_in(libusb_transfer* transfer){
int r = libusb_submit_transfer(this->transfer_in);
callback_in(transfer->buffer, transfered);
}
I can't pass MyDevice::cb_in to libusb_fill_bulk_transfer because the function pointer types are incompatible. In the same time I don't want my users to have to write a callback function with libusb_transfer* as a parameter (exposing to libusb) to pass directly to libusb_fill_bulk_transfer.
EDIT:
I tried with
void LIBUSB_CALL callback_wrapper(struct libusb_transfer* transfer){
MyDevice* dev = reinterpret_cast<MyDevice*>(transfer->user_data);
dev->cb_in(transfer);
}
but get Sementation fault (Core dumped) error
As per Max Langhof and Sam Varshavchik's comments the solution is to pass the instance of MyDevice to libusb_fill_bulk_transfer . So:
int mylib_start_transmission_async(MyDevice* dev, MyLibCallbackIn user_cb, unsigned char* buffer_in, int bufferSize){
//...
// setup transfer:
dev->transfer_in = libusb_alloc_transfer(0);
libusb_fill_bulk_transfer(dev->transfer_in, dev->dev_handle, LIBUSB_ENDPOINT_IN, dev->buffer_in,dev->bufferSize, cb_in, dev, 0);
libusb_submit_transfer(dev->transfer_in); ^^^
}
and then use the callback_wrapper as in the Edit. Thanks!

In webRTC no frame transmitted to browser from C++ code after calling onFrame in the capturer

I am trying to make my app up to date with webrtc. This is basically a desktop streaming application with a C++ application video streaming to a browser using webRTC.
My implementation used to use a bunch of deprecated stuff like SignalFrameCaptured and cricket::CapturedFrame.
Looking at webRTC right now it seems those classes/signals are not available.
Here is my capturer:
class Capturer
: public cricket::VideoCapturer,
public webrtc::DesktopCapturer::Callback
{
public:
sigslot::signal1<Capturer*> SignalDestroyed;
Capturer();
~Capturer();
void ResetSupportedFormats(const std::vector<cricket::VideoFormat>& formats);
bool CaptureFrame();
cricket::CaptureState Start(const cricket::VideoFormat& format) override;
void Stop() override;
bool IsRunning() override;
bool IsScreencast() const override;
bool GetPreferredFourccs(std::vector<uint32_t>* fourccs) override;
virtual void OnCaptureResult(webrtc::DesktopCapturer::Result result,
std::unique_ptr<webrtc::DesktopFrame> desktop_frame) override;
private:
bool running_;
int64_t initial_timestamp_;
int64_t next_timestamp_;
std::unique_ptr<webrtc::DesktopCapturer> _capturer;
};
Capturer::CaptureFrame() is called periodically from another thread and Capturer::OnCaptureResult is called as expected with a DesktopFrame as parameter.
Now looking at the implementation of OnCaptureResult:
void Capturer::OnCaptureResult(webrtc::DesktopCapturer::Result result,
std::unique_ptr<webrtc::DesktopFrame> desktopFrame)
{
if (result != webrtc::DesktopCapturer::Result::SUCCESS)
{
return; // Never called. Which leads me to conclude thedesktop capturer works
}
int width = desktopFrame->size().width();
int height = desktopFrame->size().height();
rtc::scoped_refptr<webrtc::I420Buffer> res_i420_frame = webrtc::I420Buffer::Create(width, height);
webrtc::ConvertToI420(webrtc::VideoType::kABGR,
desktopFrame->data(),
0, 0,
width, height,
0,
webrtc::kVideoRotation_0,
res_i420_frame);
webrtc::VideoFrame frame = webrtc::VideoFrame(res_i420_frame, webrtc::kVideoRotation_0, next_timestamp_ / rtc::kNumNanosecsPerMicrosec);
this->OnFrame(frame, width, height);
}
No frame are ever transmitted to the connected browser, as seen from chrome::webrtc-internals.
Back to the code, here is how I create the peerConnection:
void Conductor::connectToPeer() {
this->_peerConnectionFactory = webrtc::CreatePeerConnectionFactory();
if (!this->_peerConnectionFactory.get())
{
std::cerr << "Failed to initialize PeerConnectionFactory" << std::endl;
throw new std::runtime_error("Cannot initialize PeerConnectionFactory");
}
webrtc::PeerConnectionInterface::RTCConfiguration config;
webrtc::PeerConnectionInterface::IceServer server;
server.uri = "stun:stun.l.google.com:19302";
config.servers.push_back(server);
webrtc::FakeConstraints constraints;constraints.AddOptional(webrtc::MediaConstraintsInterface::kEnableDtlsSrtp, "true");
this->_peerConnection = this->_peerConnectionFactory->CreatePeerConnection(config, &constraints, NULL, NULL, this);
if (!this->_peerConnection.get())
{
std::cerr << "Failed to initialize PeerConnection" << std::endl;
throw new std::runtime_error("Cannot initialize PeerConnection");
}
auto capturer = new Capturer();
CapturerThread *capturerThread = new CapturerThread(capturer); // This thread sole functionis to call CaptureFrameperiodically
rtc::scoped_refptr<webrtc::VideoTrackSourceInterface> videoSource = this->_peerConnectionFactory->CreateVideoSource(capturer, NULL);
rtc::scoped_refptr<webrtc::VideoTrackInterface> videoTrack(this->_peerConnectionFactory->CreateVideoTrack("video_label", videoSource));
rtc::scoped_refptr<webrtc::MediaStreamInterface> stream = this->_peerConnectionFactory->CreateLocalMediaStream("stream_label");
stream->AddTrack(videoTrack);
if (!this->_peerConnection->AddStream(stream))
{
std::cerr << "Adding stream to PeerConnection failed" << std::endl;
throw new std::runtime_error("Cannot add stream");
}
typedef std::pair<std::string,rtc::scoped_refptr<webrtc::MediaStreamInterface>> MediaStreamPair;
this->_activeStreams.insert(MediaStreamPair(stream->label(), stream));
webrtc::SdpParseError error;
webrtc::SessionDescriptionInterface* sessionDescription(webrtc::CreateSessionDescription("offer", this->_offer, &error));
if (!sessionDescription)
{
std::cerr << "Cannot initialize session description." << std::endl;
throw new std::runtime_error("Cannot set session description");
}
this->_peerConnection->SetRemoteDescription(DummySetSessionDescriptionObserver::Create(), sessionDescription);
this->_peerConnection->CreateAnswer(this, NULL);
}
My problem is no video frames are even transmitted to the browser client even though both the capturer and the peer connection are in place as expected. Is there something I'm missing ?
I got to the bottom of this. The local description was simply not set after creating the answer.
Calling createAnswer will hopefully trigger the OnSuccess callback in the CreateSessionDescriptionObserver (in my case Conductor).
There I failed to save the answer as the local description. Here is how the OnSuccess method should be implemented:
void Conductor::OnSuccess(webrtc::SessionDescriptionInterface *desc)
{
this->_peerConnection->SetLocalDescription(DummySetSessionDescriptionObserver::Create(), desc);
}
Doing this will ultimately trigger OnIceGatheringChange with kIceGatheringComplete as parameter, meaning both sides are ready.
According with google group discuss-webrtc thread
you should implement VideoTrackSourceInterface. In my case, I used the base class AdaptedVideoTrackSource and I created a method FrameCaptured it's is called from my thread. In the method FrameCaptured I call the base method OnFrame. It's work fine !!!
class StreamSource : public rtc::AdaptedVideoTrackSource
{
void OnFrameCaptured(const webrtc::VideoFrame& frame);
}
void StreamSource::OnFrameCaptured(const webrtc::VideoFrame& frame)
{
OnFrame(frame);
}

C++ / Qt - Passing self to pthread_create

I am working on a Qt GUI that will handle a single client. I am NOT using the Qt TCP libraries or the Qt thread library. I am creating my own Server class (more or less for the experience/learning).
I wanted to make sure what I am doing with the pthread handler isn't going to come back to haunt me in the future. My question is... Is it bad practice to pass this into the pthread_create function? Could this cause problems? It seems to work ok but I am always weary about problems lurking when working with threads.
I will be happy to share more code if it is needed. Thanks for taking a look.
Server.hpp
class Server : public Socket{
public:
....
TCPSocket *accept() throw(SocketException);
static void *listen_for_clients(void *);
void start() throw(SocketException);
void set_listen() throw(SocketException);
private:
pthread_t listen_thread;
};
Server.cpp
void HandleTCPClient(TCPSocket *sock);
TCPSocket *Server::accept() throw(SocketException)
{
int new_conn_sd;
if ( (new_conn_sd = ::accept(socket_descriptor, NULL, 0)) < 0)
{
throw SocketException("Server: accept failed", true);
}
return new TCPSocket(new_conn_sd);
}
void *Server::listen_for_clients(void *ptr)
{
Server * p = (Server *)ptr;
p->set_listen();
for (;;)
{
HandleTCPClient(p->accept());
}
return 0;
}
void Server::start() throw(SocketException)
{
if(pthread_create(&listen_thread, NULL, listen_for_clients, this)) {
throw SocketException("Server: cannot create listen thread", true);
}
}
void Server::set_listen() throw(SocketException)
{
if (listen(socket_descriptor, queue_length) < 0)
{
throw SocketException("Server: set listening socket failed", true);
}
}
void HandleTCPClient(TCPSocket *sock) {
std::cout << "Handling client ";
.....
delete sock;
}

Communication between client and server is erratic

I modified thegeekinthecorner examples to be able to continuously send data.
I am using g++4.9.2.
I tried uninstalling the oficial latest OFED from here http://downloads.openfabrics.org/OFED/
OFED Distribution Software Installation Menu
1) View OFED Installation Guide
2) Install OFED Software
3) Show Installed Software
4) Configure IPoIB
5) Uninstall OFED Software
Q) Exit
Select Option [1-5]:5
Uninstalling the previous version of OFED
Running rpm -e --allmatches libibverbs libibverbs-devel libibverbs-utils libmthca libmlx4 libcxgb3 libnes libipathverbs libibcm libibumad libibumad-devel libibmad ibacm librdmacm librdmacm-utils librdmacm-devel opensm opensm-libs dapl perftest mstflint ibutils infiniband-diags qperf infinipath-psm opensm opensm-libs libipathverbs dapl libibcm libibmad libibumad libibumad-devel libibverbs libibverbs-devel libibverbs-utils libipathverbs libmthca libmlx4 librdmacm librdmacm-devel librdmacm-utils ibacm ibutils ibutils-libs libnes infinipath-psm
Failed to uninstall the previous installation
See /tmp/OFED.22320.logs/ofed_uninstall.log
[idf#node1 OFED-1.5.4-20110726-0732]$
[idf#node1 OFED-1.5.4-20110726-0732]$
If instead I just try to install it, I get this:
OFED Distribution Software Installation Menu
1) Basic (OFED modules and basic user level libraries)
2) HPC (OFED modules and libraries, MPI and diagnostic tools)
3) All packages (all of Basic, HPC)
4) Customize
Q) Exit
Select Option [1-4]:3
Please choose an implementation of MVAPICH2:
1) OFA (IB and iWARP)
2) uDAPL
Implementation [1]: 1
Enable ROMIO support [Y/n]:
Enable shared library support [Y/n]:
Enable Checkpoint-Restart support [y/N]:
Kernel 3.10.0-229.7.2.el7.x86_64 is not supported.
For the list of Supported Platforms and Operating Systems see
/mnt/gluster/Downloads/OFED-1.5.4-20110726-0732/docs/OFED_release_notes.txt
[idf#node1 OFED-1.5.4-20110726-0732]$
[idf#node2 Release]$ lspci | grep -i mel
02:00.0 InfiniBand: Mellanox Technologies MT26428 [ConnectX VPI PCIe 2.0 5GT/s - IB QDR / 10GigE] (rev b0)
[idf#node2 Release]$
[idf#node1 Release]$ ibv_devinfo
hca_id: mlx4_0
transport: InfiniBand (0)
fw_ver: 2.7.200
node_guid: 0025:90ff:ff1a:081c
sys_image_guid: 0025:90ff:ff1a:081f
vendor_id: 0x02c9
vendor_part_id: 26428
hw_ver: 0xB0
board_id: SM_2092000001000
phys_port_cnt: 1
port: 1
state: PORT_ACTIVE (4)
max_mtu: 4096 (5)
active_mtu: 4096 (5)
sm_lid: 1
port_lid: 2
port_lmc: 0x00
link_layer: InfiniBand
[idf#node1 Release]$ ifconfig -a
ib0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 2044
inet 192.168.0.1 netmask 255.255.255.0 broadcast 192.168.0.255
inet6 fe80::225:90ff:ff1a:71 prefixlen 64 scopeid 0x20<link>
Infiniband hardware address can be incorrect! Please read BUGS section in ifconfig(8).
infiniband 80:00:00:48:FE:80:00:00:00:00:00:00:00:00:00:00:00:00:00:00 txqueuelen 256 (InfiniBand)
RX packets 5 bytes 280 (280.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 27 overruns 0 carrier 0 collisions 0
Below is the client and server. When I run this programs, the clients will send messages, but the number of messages it sends is erratic, error messages are often
Client:
#include <iostream>
#include <thread>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <rdma/rdma_cma.h>
#define TEST_NZ(x) do { if ( (x)) die("error: " #x " failed (returned non-zero)." ); } while (0)
#define TEST_Z(x) do { if (!(x)) die("error: " #x " failed (returned zero/null)."); } while (0)
const int BUFFER_SIZE = 2048;
const int TIMEOUT_IN_MS = 500; /* ms */
struct context
{
struct ibv_context *ctx;
struct ibv_pd *pd;
struct ibv_cq *cq;
struct ibv_comp_channel *comp_channel;
pthread_t cq_poller_thread;
};
struct connection
{
struct rdma_cm_id *id;
struct ibv_qp *qp;
struct ibv_mr *recv_mr;
struct ibv_mr *send_mr;
char *recv_region;
char *send_region;
int num_completions;
};
static pthread_t msgThread;
static void die(const char *reason);
static void build_context(struct ibv_context *verbs);
static void build_qp_attr(struct ibv_qp_init_attr *qp_attr);
static void * poll_cq(void *);
static void post_receives(struct connection *conn);
static void register_memory(struct connection *conn);
static int on_addr_resolved(struct rdma_cm_id *id);
static void on_completion(struct ibv_wc *wc);
static int on_connection(void *context);
static int on_disconnect(struct rdma_cm_id *id);
static int on_event(struct rdma_cm_event *event);
static int on_route_resolved(struct rdma_cm_id *id);
static struct context *s_ctx = NULL;
#include <mutex> // std::mutex, std::unique_lock
#include <condition_variable> // std::condition_variable
std::mutex mtx;
std::condition_variable cv;
bool ok_to_send_next_message = 1;
bool message_available()
{
return 0 != ok_to_send_next_message;
}
int main(int argc, char **argv)
{
struct addrinfo *addr;
struct rdma_cm_event *event = NULL;
struct rdma_cm_id *conn= NULL;
struct rdma_event_channel *ec = NULL;
if (argc != 3)
die("usage: client <server-address> <server-port>");
TEST_NZ(getaddrinfo(argv[1], argv[2], NULL, &addr));
TEST_Z(ec = rdma_create_event_channel());
TEST_NZ(rdma_create_id(ec, &conn, NULL, RDMA_PS_TCP));
TEST_NZ(rdma_resolve_addr(conn, NULL, addr->ai_addr, TIMEOUT_IN_MS));
freeaddrinfo(addr);
while (0 == rdma_get_cm_event(ec, &event))
//while (rdma_get_cm_event(ec, &event))
{
std::cout << "rdma_get_cm_event\n";
struct rdma_cm_event event_copy;
memcpy(&event_copy, event, sizeof(*event));
rdma_ack_cm_event(event);
if (on_event(&event_copy))
break;
}
rdma_destroy_event_channel(ec);
return 0;
}
void die(const char *reason)
{
fprintf(stderr, "%s\n", reason);
exit(EXIT_FAILURE);
}
void build_context(struct ibv_context *verbs)
{
if (s_ctx)
{
if (s_ctx->ctx != verbs)
die("cannot handle events in more than one context.");
return;
}
s_ctx = (struct context *)malloc(sizeof(struct context));
s_ctx->ctx = verbs;
TEST_Z(s_ctx->pd = ibv_alloc_pd(s_ctx->ctx));
TEST_Z(s_ctx->comp_channel = ibv_create_comp_channel(s_ctx->ctx));
TEST_Z(s_ctx->cq = ibv_create_cq(s_ctx->ctx, 100, NULL, s_ctx->comp_channel, 0)); /* cqe=10 is arbitrary */
TEST_NZ(ibv_req_notify_cq(s_ctx->cq, 0));
TEST_NZ(pthread_create(&s_ctx->cq_poller_thread, NULL, poll_cq, NULL));
}
void *SendMessages(void *context)
{
static int loopcount = 0;
while(1)
{
std::unique_lock<std::mutex> lck(mtx);
cv.wait(lck, message_available);
//std::this_thread::sleep_for(std::chrono::microseconds(50));
ok_to_send_next_message = 0;
struct connection *conn = (struct connection *)context;
struct ibv_send_wr wr, *bad_wr = NULL;
struct ibv_sge sge;
std::cout << "looping send..." << loopcount << '\n' << std::flush;
memset(&wr, 0, sizeof(wr));
wr.wr_id = (uintptr_t)conn;
wr.opcode = IBV_WR_SEND;
wr.sg_list = &sge;
wr.num_sge = 1;
wr.send_flags = IBV_SEND_SIGNALED;
sge.addr = (uintptr_t)conn->send_region;
sge.length = BUFFER_SIZE;
sge.lkey = conn->send_mr->lkey;
snprintf(conn->send_region, BUFFER_SIZE, "message from active/client side with count %d", loopcount++);
TEST_NZ(ibv_post_send(conn->qp, &wr, &bad_wr));
}
}
void build_qp_attr(struct ibv_qp_init_attr *qp_attr)
{
std::cout << "build_qp_attr\n";
memset(qp_attr, 0, sizeof(*qp_attr));
qp_attr->send_cq = s_ctx->cq;
qp_attr->recv_cq = s_ctx->cq;
qp_attr->qp_type = IBV_QPT_RC;
qp_attr->cap.max_send_wr = 100;
qp_attr->cap.max_recv_wr = 100;
qp_attr->cap.max_send_sge = 1;
qp_attr->cap.max_recv_sge = 1;
}
void * poll_cq(void *ctx)
{
struct ibv_cq *cq;
struct ibv_wc wc;
while (1)
{
TEST_NZ(ibv_get_cq_event(s_ctx->comp_channel, &cq, &ctx));
ibv_ack_cq_events(cq, 1);
TEST_NZ(ibv_req_notify_cq(cq, 0));
int ne;
struct ibv_wc wc;
do
{
std::cout << "polling\n";
ne = ibv_poll_cq(cq, 1, &wc);
}
while(ne == 0);
on_completion(&wc);
//if (wc.opcode == IBV_WC_SEND)
if (wc.status == IBV_WC_SUCCESS)
{
{
ok_to_send_next_message = 1;
//while (message_available()) std::this_thread::yield();
//std::cout << "past yield\n";
std::unique_lock<std::mutex> lck(mtx);
cv.notify_one();
}
}
}
return NULL;
}
void post_receives(struct connection *conn)
{
std::cout << "post_receives\n";
struct ibv_recv_wr wr, *bad_wr = NULL;
struct ibv_sge sge;
wr.wr_id = (uintptr_t)conn;
wr.next = NULL;
wr.sg_list = &sge;
wr.num_sge = 1;
sge.addr = (uintptr_t)conn->recv_region;
sge.length = BUFFER_SIZE;
sge.lkey = conn->recv_mr->lkey;
TEST_NZ(ibv_post_recv(conn->qp, &wr, &bad_wr));
}
void register_memory(struct connection *conn)
{
std::cout << "register_memory\n";
conn->send_region = (char *)malloc(BUFFER_SIZE);
conn->recv_region = (char *)malloc(BUFFER_SIZE);
TEST_Z(conn->send_mr = ibv_reg_mr(
s_ctx->pd,
conn->send_region,
BUFFER_SIZE,
IBV_ACCESS_LOCAL_WRITE | IBV_ACCESS_REMOTE_WRITE));
TEST_Z(conn->recv_mr = ibv_reg_mr(
s_ctx->pd,
conn->recv_region,
BUFFER_SIZE,
IBV_ACCESS_LOCAL_WRITE | IBV_ACCESS_REMOTE_WRITE));
}
int on_addr_resolved(struct rdma_cm_id *id)
{
std::cout << "on_addr_resolved\n";
struct ibv_qp_init_attr qp_attr;
struct connection *conn;
build_context(id->verbs);
build_qp_attr(&qp_attr);
TEST_NZ(rdma_create_qp(id, s_ctx->pd, &qp_attr));
id->context = conn = (struct connection *)malloc(sizeof(struct connection));
conn->id = id;
conn->qp = id->qp;
conn->num_completions = 0;
register_memory(conn);
post_receives(conn);
TEST_NZ(rdma_resolve_route(id, TIMEOUT_IN_MS));
return 0;
}
void on_completion(struct ibv_wc *wc)
{
std::cout << "on_completion\n";
struct connection *conn = (struct connection *)(uintptr_t)wc->wr_id;
if (wc->status != IBV_WC_SUCCESS)
{
//die("\ton_completion: status is not IBV_WC_SUCCESS.");
printf("\ton_completion: status is not IBV_WC_SUCCESS.");
printf("\t it is %d ", wc->status);
}
printf("\n");
if (wc->opcode & IBV_WC_RECV)
printf("\treceived message: %s\n", conn->recv_region);
else if (wc->opcode == IBV_WC_SEND)
printf("\tsend completed successfully.\n");
else
die("\ton_completion: completion isn't a send or a receive.");
if (5 == ++conn->num_completions)
rdma_disconnect(conn->id);
}
int on_connection(void *context)
{
std::cout << "on_connection\n";
TEST_NZ(pthread_create(&msgThread, NULL, SendMessages, context));
return 0;
}
int on_disconnect(struct rdma_cm_id *id)
{
struct connection *conn = (struct connection *)id->context;
printf("disconnected.\n");
rdma_destroy_qp(id);
ibv_dereg_mr(conn->send_mr);
ibv_dereg_mr(conn->recv_mr);
free(conn->send_region);
free(conn->recv_region);
free(conn);
rdma_destroy_id(id);
return 1; /* exit event loop */
}
int on_route_resolved(struct rdma_cm_id *id)
{
struct rdma_conn_param cm_params;
printf("route resolved.\n");
memset(&cm_params, 0, sizeof(cm_params));
TEST_NZ(rdma_connect(id, &cm_params));
return 0;
}
int on_event(struct rdma_cm_event *event)
{
int r = 0;
if (event->event == RDMA_CM_EVENT_ADDR_RESOLVED)
r = on_addr_resolved(event->id);
else if (event->event == RDMA_CM_EVENT_ROUTE_RESOLVED)
r = on_route_resolved(event->id);
else if (event->event == RDMA_CM_EVENT_ESTABLISHED)
r = on_connection(event->id->context);
else if (event->event == RDMA_CM_EVENT_DISCONNECTED)
r = on_disconnect(event->id);
else
die("on_event: unknown event.");
return r;
}
Server:
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <inttypes.h>
#include <rdma/rdma_cma.h>
#define TEST_NZ(x) do { if ( (x)) die("error: " #x " failed (returned non-zero)." ); } while (0)
#define TEST_Z(x) do { if (!(x)) die("error: " #x " failed (returned zero/null)."); } while (0)
const int BUFFER_SIZE = 2048;
struct context
{
struct ibv_context *ctx;
struct ibv_pd *pd;
struct ibv_cq *cq;
struct ibv_comp_channel *comp_channel;
pthread_t cq_poller_thread;
};
struct connection
{
struct ibv_qp *qp;
struct ibv_mr *recv_mr;
struct ibv_mr *send_mr;
char *recv_region;
char *send_region;
};
static void die(const char *reason);
static void build_context(struct ibv_context *verbs);
static void build_qp_attr(struct ibv_qp_init_attr *qp_attr);
static void * poll_cq(void *);
static void post_receives(struct connection *conn);
static void register_memory(struct connection *conn);
static void on_completion(struct ibv_wc *wc);
static int on_connect_request(struct rdma_cm_id *id);
static int on_connection(void *context);
static int on_disconnect(struct rdma_cm_id *id);
static int on_event(struct rdma_cm_event *event);
static struct context *s_ctx = NULL;
int main(int argc, char **argv)
{
struct sockaddr_in6 addr;
struct rdma_cm_event *event = NULL;
struct rdma_cm_id *listener = NULL;
struct rdma_event_channel *ec = NULL;
uint16_t port = 0;
memset(&addr, 0, sizeof(addr));
addr.sin6_family = AF_INET6;
TEST_Z(ec = rdma_create_event_channel());
TEST_NZ(rdma_create_id(ec, &listener, NULL, RDMA_PS_TCP));
TEST_NZ(rdma_bind_addr(listener, (struct sockaddr *)&addr));
TEST_NZ(rdma_listen(listener, 100)); /* backlog=10 is arbitrary */
//printf("[ %"PRIu32" ]\n", *addr.sin6_addr.s6_addr32);
port = ntohs(rdma_get_src_port(listener));
printf("listening on port %d.\n", port);
while (rdma_get_cm_event(ec, &event) == 0)
{
struct rdma_cm_event event_copy;
memcpy(&event_copy, event, sizeof(*event));
rdma_ack_cm_event(event);
if (on_event(&event_copy))
break;
}
rdma_destroy_id(listener);
rdma_destroy_event_channel(ec);
return 0;
}
void die(const char *reason)
{
fprintf(stderr, "%s\n", reason);
exit(EXIT_FAILURE);
}
void build_context(struct ibv_context *verbs)
{
if (s_ctx)
{
if (s_ctx->ctx != verbs)
die("cannot handle events in more than one context.");
return;
}
s_ctx = (struct context *)malloc(sizeof(struct context));
s_ctx->ctx = verbs;
TEST_Z(s_ctx->pd = ibv_alloc_pd(s_ctx->ctx));
TEST_Z(s_ctx->comp_channel = ibv_create_comp_channel(s_ctx->ctx));
TEST_Z(s_ctx->cq = ibv_create_cq(s_ctx->ctx, 100, NULL, s_ctx->comp_channel, 0)); /* cqe=10 is arbitrary */
TEST_NZ(ibv_req_notify_cq(s_ctx->cq, 0));
TEST_NZ(pthread_create(&s_ctx->cq_poller_thread, NULL, poll_cq, NULL));
}
void build_qp_attr(struct ibv_qp_init_attr *qp_attr)
{
memset(qp_attr, 0, sizeof(*qp_attr));
qp_attr->send_cq = s_ctx->cq;
qp_attr->recv_cq = s_ctx->cq;
qp_attr->qp_type = IBV_QPT_RC;
qp_attr->cap.max_send_wr = 100;
qp_attr->cap.max_recv_wr = 100;
qp_attr->cap.max_send_sge = 1;
qp_attr->cap.max_recv_sge = 1;
}
void * poll_cq(void *ctx)
{
struct ibv_cq *cq;
struct ibv_wc wc;
while (1)
{
TEST_NZ(ibv_get_cq_event(s_ctx->comp_channel, &cq, &ctx));
ibv_ack_cq_events(cq, 1);
TEST_NZ(ibv_req_notify_cq(cq, 0));
while (ibv_poll_cq(cq, 1, &wc))
{
std::cout << "polling\n";
on_completion(&wc);
}
}
return NULL;
}
void post_receives(struct connection *conn)
{
std::cout << "post_receives\n";
struct ibv_recv_wr wr, *bad_wr = NULL;
struct ibv_sge sge;
wr.wr_id = (uintptr_t)conn;
wr.next = NULL;
wr.sg_list = &sge;
wr.num_sge = 1;
sge.addr = (uintptr_t)conn->recv_region;
sge.length = BUFFER_SIZE;
sge.lkey = conn->recv_mr->lkey;
TEST_NZ(ibv_post_recv(conn->qp, &wr, &bad_wr));
}
void register_memory(struct connection *conn)
{
conn->send_region = (char *)malloc(BUFFER_SIZE);
conn->recv_region = (char *)malloc(BUFFER_SIZE);
TEST_Z(conn->send_mr = ibv_reg_mr(
s_ctx->pd,
conn->send_region,
BUFFER_SIZE,
IBV_ACCESS_LOCAL_WRITE | IBV_ACCESS_REMOTE_WRITE));
TEST_Z(conn->recv_mr = ibv_reg_mr(
s_ctx->pd,
conn->recv_region,
BUFFER_SIZE,
IBV_ACCESS_LOCAL_WRITE | IBV_ACCESS_REMOTE_WRITE));
}
void on_completion(struct ibv_wc *wc)
{
if (wc->status != IBV_WC_SUCCESS)
die("on_completion: status is not IBV_WC_SUCCESS.");
if (wc->opcode & IBV_WC_RECV)
{
struct connection *conn = (struct connection *)(uintptr_t)wc->wr_id;
post_receives(conn);
printf("received message: %s\n", conn->recv_region);
}
else if (wc->opcode == IBV_WC_SEND)
{
printf("send completed successfully.\n");
}
}
int on_connect_request(struct rdma_cm_id *id)
{
struct ibv_qp_init_attr qp_attr;
struct rdma_conn_param cm_params;
struct connection *conn;
printf("received connection request.\n");
build_context(id->verbs);
build_qp_attr(&qp_attr);
TEST_NZ(rdma_create_qp(id, s_ctx->pd, &qp_attr));
id->context = conn = (struct connection *)malloc(sizeof(struct connection));
conn->qp = id->qp;
register_memory(conn);
post_receives(conn);
memset(&cm_params, 0, sizeof(cm_params));
TEST_NZ(rdma_accept(id, &cm_params));
return 0;
}
int on_connection(void *context)
{
struct connection *conn = (struct connection *)context;
struct ibv_send_wr wr, *bad_wr = NULL;
struct ibv_sge sge;
snprintf(conn->send_region, BUFFER_SIZE, "message from passive/server side with pid %d", getpid());
printf("connected. posting send...\n");
memset(&wr, 0, sizeof(wr));
wr.opcode = IBV_WR_SEND;
wr.sg_list = &sge;
wr.num_sge = 1;
wr.send_flags = IBV_SEND_SIGNALED;
sge.addr = (uintptr_t)conn->send_region;
sge.length = BUFFER_SIZE;
sge.lkey = conn->send_mr->lkey;
TEST_NZ(ibv_post_send(conn->qp, &wr, &bad_wr));
return 0;
}
int on_disconnect(struct rdma_cm_id *id)
{
struct connection *conn = (struct connection *)id->context;
printf("peer disconnected.\n");
rdma_destroy_qp(id);
ibv_dereg_mr(conn->send_mr);
ibv_dereg_mr(conn->recv_mr);
free(conn->send_region);
free(conn->recv_region);
free(conn);
rdma_destroy_id(id);
return 0;
}
int on_event(struct rdma_cm_event *event)
{
std::cout << "on_event\n";
int r = 0;
if (event->event == RDMA_CM_EVENT_CONNECT_REQUEST)
r = on_connect_request(event->id);
else if (event->event == RDMA_CM_EVENT_ESTABLISHED)
r = on_connection(event->id->context);
else if (event->event == RDMA_CM_EVENT_DISCONNECTED)
r = on_disconnect(event->id);
else
die("on_event: unknown event.");
return r;
}
Here are a couple of runs. Totally random the number of message sent:
[idf#node1 Release]$ ./TGKITCClient 192.168.0.1 47819
rdma_get_cm_event
on_addr_resolved
build_qp_attr
register_memory
post_receives
rdma_get_cm_event
route resolved.
rdma_get_cm_event
on_connection
looping send...0
polling
on_completion
received message: message from passive/server side with pid 4188
polling
on_completion
send completed successfully.
looping send...1
polling
on_completion
send completed successfully.
^C
[idf#node1 Release]$
And then
[idf#node1 Release]$ ./TGKITCClient 192.168.0.1 55148
rdma_get_cm_event
on_addr_resolved
build_qp_attr
register_memory
post_receives
rdma_get_cm_event
route resolved.
rdma_get_cm_event
on_connection
looping send...0
polling
on_completion
received message: message from passive/server side with pid 4279
polling
on_completion
send completed successfully.
looping send...1
polling
on_completion
send completed successfully.
looping send...2
polling
on_completion
send completed successfully.
looping send...3
polling
on_completion
send completed successfully.
looping send...4
polling
on_completion
send completed successfully.
looping send...5
polling
on_completion
send completed successfully.
looping send...6
polling
on_completion
send completed successfully.
looping send...7
polling
on_completion
send completed successfully.
looping send...8
rdma_get_cm_event
disconnected.
polling
on_completion
send completed successfully.
on_completion: status is not IBV_WC_SUCCESS. it is 5 [idf#node1 Release]$
Here is the server side:
on_event
peer disconnected.
on_event
received connection request.
post_receives
on_event
connected. posting send...
polling
send completed successfully.
polling
post_receives
received message: message from active/client side with count 0
polling
post_receives
received message: message from active/client side with count 1
polling
post_receives
received message: message from active/client side with count 2
polling
post_receives
received message: message from active/client side with count 3
polling
post_receives
received message: message from active/client side with count 4
polling
post_receives
received message: message from active/client side with count 5
polling
post_receives
received message: message from active/client side with count 6
polling
post_receives
received message: message from active/client side with count 7
on_event
peer disconnected.
Make sure that the most recent drivers and firmware on the cards are installed. Beyond that, using the RDMA packages included with most OS distributions when trying to run IB is a dangerous game to play.
It is strongly recommended that for applications like these the Open Fabrics Enterprise Distribution should be used to provide openib, opensm and a variety of other useful infiniband related packages for analysis diagnostics and tuning of a network. The official OFED packages can be found on the OpenFabrics website.
Based on the question it looks like IPoIB is being used but the specific configuration is not mentioned. IPoIB is not necessarily the best way to take advantages of the hardware resources available in the IB cards.
In addition to those considerations making sure that the subnetmanager is setup and configured correctly. Some switches have built-in subnet managers that can be access and configured through a management interface, in other cases it might make more sense to run and configure the subnet manager on one of the nodes that you are using. OpenSM is a common subnet manager that is included with OFED distributions and there are many online guides available for setting up and configuring a subnet manager based on the type of network being setup.
OFED also includes a variety of IB testing and profiling tools. ibdiagnet is a useful tool for debugging IB network issues. And there are many guides available online that show different ways to make use of the tool as well as the other tools included in OFED.
Depending on the type of IB switch used there may additionally be some network management and diagnostic tools that would allow for further analysis of the network. The configuration of IB hardware and the low-level software that manages it is sometimes more critical to overall performance than the actual code being run. But with that being said recompiling and linking to relevant libraries from the correct version of OFED might be advisable if significant software of hardware configuration changes are made.

mongoose web server helloworld program

I came across an embedded web server named mongoose and http://code.google.com/p/mongoose/ and I read the wiki it was great and i searched for some sample hello world program but i couldn't find it... i found some example but that was written in c++ for windows and can any one provide an example c program to run this webserver..
It is quite simple, first you need to implement the call back function:
void *event_handler(enum mg_event event,
struct mg_connection *conn) {
const struct mg_request_info *request_info = mg_get_request_info(conn);
static void* done = "done";
if (event == MG_NEW_REQUEST) {
if (strcmp(request_info->uri, "/hello") == 0) {
// handle c[renderer] request
if(strcmp(request_info->request_method, "GET") != 0) {
// send error (we only care about HTTP GET)
mg_printf(conn, "HTTP/1.1 %d Error (%s)\r\n\r\n%s",
500,
"we only care about HTTP GET",
"we only care about HTTP GET");
// return not null means we handled the request
return done;
}
// handle your GET request to /hello
char* content = "Hello World!";
char* mimeType = "text/plain";
int contentLength = strlen(content);
mg_printf(conn,
"HTTP/1.1 200 OK\r\n"
"Cache: no-cache\r\n"
"Content-Type: %s\r\n"
"Content-Length: %d\r\n"
"\r\n",
mimeType,
contentLength);
mg_write(conn, content, contentLength);
return done;
}
}
// in this example i only handle /hello
mg_printf(conn, "HTTP/1.1 %d Error (%s)\r\n\r\n%s",
500, /* This the error code you want to send back*/
"Invalid Request.",
"Invalid Request.");
return done;
}
// No suitable handler found, mark as not processed. Mongoose will
// try to serve the request.
return NULL;
}
Then you need to start the server:
int main(int argc, char **argv) {
/* Default options for the HTTP server */
const char *options[] = {
"listening_ports", "8081",
"num_threads", "10",
NULL
};
/* Initialize HTTP layer */
static struct mg_context *ctx;
ctx = mg_start(&event_handler, options);
if(ctx == NULL) {
exit(EXIT_FAILURE);
}
puts("Server running, press enter to exit\n");
getchar();
mg_stop(ctx);
return EXIT_SUCCESS;
}
I wrote a C++ REST service library that uses Mongoose. Here's a simple example:
#include <iostream>
#include <server/server.hpp>
int main()
{
using namespace pwned::server;
Server server;
server.Get("/", [](mg_event*, Params const &) {
return Server::response("Hello!");
});
std::cin.get();
}
Based on
https://github.com/nurettin/pwned/blob/master/examples/server/basics/server.cpp
Compile application: $ cc my_app.c mongoose.c
#include "mongoose.h" // Include Mongoose API definitions
static const char *s_http_port = "8089";
// Define an event handler function
static void ev_handler(struct mg_connection *nc, int ev, void *ev_data)
{
struct mbuf *io = &nc->recv_mbuf;
switch (ev)
{
case MG_EV_RECV:
// This event handler implements simple TCP echo server
mg_send(nc, io->buf, io->len); // Echo received data back
mbuf_remove(io, io->len); // Discard data from recv buffer
break;
default:
break;
}
}
int main(void)
{
struct mg_mgr mgr;
mg_mgr_init(&mgr, NULL); // Initialize event manager object
// Note that many connections can be added to a single event manager
// Connections can be created at any point, e.g. in event handler function
mg_bind(&mgr, s_http_port, ev_handler); // Create listening connection and add it to the event manager
for (;;)
{
// Start infinite event loop
mg_mgr_poll(&mgr, 1000);
}
mg_mgr_free(&mgr);
return 0;
}
For anyone looking at this thread - from the mongoose library author (me).
Mongoose web server has long ago moved to https://github.com/cesanta/mongoose
It has a comprehensive list of examples, starting from a simplest ones, to the more complex ones, see examples directory in the repository. The minimal static HTTP server goes as follows:
#include "mongoose.h"
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
struct mg_http_serve_opts opts = {.root_dir = "."}; // Serve local dir
if (ev == MG_EV_HTTP_MSG) mg_http_serve_dir(c, ev_data, &opts);
}
int main(int argc, char *argv[]) {
struct mg_mgr mgr;
mg_mgr_init(&mgr); // Init manager
mg_http_listen(&mgr, "http://localhost:8000", fn, &mgr); // Setup listener
for (;;) mg_mgr_poll(&mgr, 1000); // Event loop
mg_mgr_free(&mgr); // Cleanup
return 0;
}