How to add an std::pair to a shared memory queue - std-pair

I am trying to add an std::pair to a shared memory queue. This doesn't compile.
What is the correct way to add an std::pair to a shared memory queue?
#include <boost/lockfree/spsc_queue.hpp> // ring buffer
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/string.hpp>
namespace bip = boost::interprocess;
namespace shm
{
typedef bip::allocator<char, bip::managed_shared_memory::segment_manager> char_alloc;
typedef bip::basic_string<char, std::char_traits<char>, char_alloc > shared_string;
typedef boost::lockfree::spsc_queue<
shared_string,
boost::lockfree::capacity<200>
> ring_buffer;
}
#include <unistd.h>
// Ringbuffer fully constructed in shared memory. The element std::pair are
// also allocated from the same shared memory segment.
shm::ring_buffer *queue;
int main()
{
// create segment and corresponding allocator
bip::managed_shared_memory segment(bip::open_or_create, "MySharedMemory", 65536);
typedef std::pair<float, float> ValueType;
typedef bip::allocator<ValueType, bip::managed_shared_memory::segment_manager>
ShmemAllocator;
//Initialize the shared memory STL-compatible allocator
ShmemAllocator pair_alloc (segment.get_segment_manager());
queue = segment.find_or_construct<shm::ring_buffer>("queue")();
for (int i = 0; i < 3; i++)
{
//Do I really need a pointer to shared memory?
ValueType *reading = segment.construct<ValueType>
("Sensor Pacific") //name of the object
(57.3, 57.8); //ctor first argument
queue->push(reading); // THIS_FAILS_TO_COMPILE
}
}
I have also tried
ValueType t = std::make_pair<float, float>(57.3, 57.8);
queue->push(ShmemAllocator(t, pair_alloc));
If I change the type of queue it also doesn't work:
shm::ring_buffer<ValueType> *queue;
I know I need to modify this section of code below so that the queue is of type shared_std_pair and not shared_string, but not sure how to do it. The part that gets me is the typedef bip::basic_string<char, std::char_traits<char>, char_alloc > shared_string
I need an shared_std_pair
namespace shm
{
typedef bip::allocator<char, bip::managed_shared_memory::segment_manager> char_alloc;
typedef bip::basic_string<char, std::char_traits<char>, char_alloc > shared_string;
typedef boost::lockfree::spsc_queue<
shared_string,
boost::lockfree::capacity<200>
> ring_buffer;
}
It feels like I have to use something like std::uses_allocator<std::tuple> but I don't see one for std::pair.

Related

statically testing the type of an STL iterator forward/bidirectional/random access?

Is there a way to test statically the type of an iterator and have a template which depends on it execute different but code depending on the type(since algorithm choice changes)?
You can use std::iterator_traits<T>::iterator_category to get the category of the iterator. Example:
#include <vector>
#include <type_traits>
int main()
{
std::vector<int> v;
static_assert(std::is_same_v<
std::iterator_traits<decltype(v.begin())>::iterator_category,
std::random_access_iterator_tag>);
}
You can then overload on the tag types to provide static dispatch:
void foo(std::random_access_iterator_tag); // (0)
void foo(std::bidirectional_iterator_tag); // (1)
int main()
{
std::vector<int> v;
std::list<int> v;
foo(std::iterator_traits<decltype(v.begin())>::iterator_category{}); // calls 0
foo(std::iterator_traits<decltype(l.begin())>::iterator_category{}); // calls 1
}

exposing a function with 2D slice as a parameter in a c-shared library (to be used in Java via JNA and C)

I am trying to write a simple matrix operations API using go and expose the APIs as a shared library. This shared library will be used from Java(using JNA) and from C.
The documentation is very sparse about using any data type beyond simple int or string as function parameters.
My requirement is to expose functions with 1 or more 2D slices as parameters AND also as return types. I am not able to figure out if such a thing is supported.
Is this possible? Are there any examples for this?
I think the key point is to have a look to the c bindings of slice,string and int generated by go build tool. I not tried 2D slice, but it should no different to 1D slice with unsafe pointer converter, maybe just be one more time allocation and convertion.
I'm not sure it's the best way, but here's the example for 1D slice:
the go part:
import "C"
//export CFoo
func CFoo(content []byte) string{
var ret []byte
//blablabla to get ret
cbuf := unsafe.Pointer(C.malloc(C.size_t(len(ret))))
C.memcpy(cbuf, unsafe.Pointer(&ret[0]), C.size_t(len(ret)))
var finalString string
hdr := (*reflect.StringHeader)(unsafe.Pointer(&finalString))
hdr.Data = uintptr(unsafe.Pointer(cbuf))
hdr.Len = len(ret)
return finalString
}
compile with -buildmode=c-shared, to get libmygo.so.
I not know JNA, expecting it like JNI. the JNI part as well as pure C part:
#include <stdio.h>
#include <jni.h>
#include <string.h>
typedef signed char GoInt8;
typedef unsigned char GoUint8;
typedef short GoInt16;
typedef unsigned short GoUint16;
typedef int GoInt32;
typedef unsigned int GoUint32;
typedef long long GoInt64;
typedef unsigned long long GoUint64;
typedef GoInt32 GoInt;
typedef GoUint32 GoUint;
typedef __SIZE_TYPE__ GoUintptr;
typedef float GoFloat32;
typedef double GoFloat64;
typedef float _Complex GoComplex64;
typedef double _Complex GoComplex128;
typedef struct { const char *p; GoInt n; } GoString;
typedef void *GoMap;
typedef void *GoChan;
typedef struct { void *t; void *v; } GoInterface;
typedef struct { void *data; GoInt len; GoInt cap; } GoSlice;
JNIEXPORT JNICALL jbyteArray Java_com_mynextev_infotainment_app_myev_Native_foo(JNIEnv* env, jobject obj,jbyteArray content){
JNIEnv ienv = *env;
void * Ccontent = ienv->GetByteArrayElements(env, content, 0);
int Lcontent = ienv->GetArrayLength(env, content);
GoSlice Gcontent = {Ccontent, Lcontent, Lcontent};
if(!gret.n){
printf("jni CDoAESEnc");
return NULL;
}
jbyteArray ret = ienv->NewByteArray(env, gret.n);
ienv->SetByteArrayRegion(env, ret, 0, gret.n, gret.p);
free((void*)gret.p);
ienv->ReleaseByteArrayElements(env, content, Ccontent, JNI_ABORT);
return ret;
}
build it with libmygo.so.
finally you get two so files. one for C which can be used standalone; one for Java which must be used with libmygo.so together.

std::scoped_allocator_adapator code fails to compile with vector of strings

In the hopes of using it for my needs I'm playing with std::scoped_allocator_adaptor. This minimal example uses strings and vector, but it fails to compile with on both clang++ and g++.
#include <string>
#include <iostream>
#include <vector>
#include <scoped_allocator>
struct SomeStruct
{
template <typename T>
using Allocator = std::allocator<T>;
template <typename T>
using ScopedAllocator = std::scoped_allocator_adaptor<Allocator<T>>;
using String = std::basic_string<char, std::char_traits<char>, Allocator<char>>;
template <typename T>
using Vector = std::vector<T, ScopedAllocator<T>>;
SomeStruct()
: s{allocator},
v(ScopedAllocator<String>{allocator})
{
}
std::allocator<char> allocator;
String s;
Vector<String> v;
};
int main(int argc, char* argv[])
{
SomeStruct ss;
std::cout << "faffing with vector\n";
ss.v.push_back("hello"); // *** This fails to compile.
std::cout << ss.v[0] << "\n";
return 0;
}
In reality std::allocator won't be used, it's just a placeholder. This attempt was influenced by http://www.stroustrup.com/C++11FAQ.html#scoped-allocator
The compiler error message is lengthy, but boils down to the fact that a suitable constructor cannot be found.
Ubuntu clang version 3.4-1ubuntu3 (tags/RELEASE_34/final) (based on LLVM 3.4)
g++ (Ubuntu 4.8.4-2ubuntu1~14.04) 4.8.4
and with C++14 at ideone.com

how to create multiple containers in boost shared memory?

Constructing multiple objects in shared memory is possible as shown in this example:
#include <boost/interprocess/managed_shared_memory.hpp>
#include <functional>
#include <iostream>
using namespace boost::interprocess;
void construct_objects(managed_shared_memory &managed_shm)
{
managed_shm.construct<int>("Integer")(99);
managed_shm.construct<float>("Float")(3.14);
}
int main()
{
shared_memory_object::remove("Boost");
managed_shared_memory managed_shm{open_or_create, "Boost", 1024};
auto atomic_construct = std::bind(construct_objects,
std::ref(managed_shm));
managed_shm.atomic_func(atomic_construct);
std::cout << *managed_shm.find<int>("Integer").first << '\n';
std::cout << *managed_shm.find<float>("Float").first << '\n';
}
But when I try to create two vectors or a vector and a list, I run into problems with the memory allocation. Is there a way to create multiple containers in a single shared memory in Boost?
I had a look at managed_memory_impl.hpp, but it wasn't of much help either.
This is my code (you have to link it with lib pthread and librt):
#include <boost/interprocess/mapped_region.hpp>
#include <boost/interprocess/sync/interprocess_semaphore.hpp>
#include <boost/interprocess/containers/vector.hpp>
#include <boost/interprocess/containers/list.hpp>
#include <boost/interprocess/managed_shared_memory.hpp>
#include <cstdlib> //std::system
#include <cstddef>
#include <cassert>
#include <utility>
#include <iostream>
typedef boost::interprocess::allocator<int, boost::interprocess::managed_shared_memory::segment_manager> ShmemAllocator; //Define an STL compatible allocator of ints that allocates from the managed_shared_memory. This allocator will allow placing containers in the segment
typedef boost::interprocess::vector<int, ShmemAllocator> MyVector; //Alias a vector that uses the previous STL-like allocator so that allocates its values from the segment
typedef boost::interprocess::allocator<int, boost::interprocess::managed_shared_memory::segment_manager> ShmemListAllocator;
typedef boost::interprocess::list<int, ShmemListAllocator> MyList;
int main(int argc, char *argv[])
{
//Construct managed shared memory
boost::interprocess::managed_shared_memory segment(boost::interprocess::create_only, "MySharedMemory", 65536);
//const ShmemAllocator alloc_inst(segment.get_segment_manager());
MyVector *instance = segment.construct<MyVector>("MyType instance")(segment.get_segment_manager());
MyVector *instance2 = segment.construct<MyVector>("MyType instance")(segment.get_segment_manager());
MyList *instance3 = segment.construct<MyList>("MyList instance")(segment.get_segment_manager());
return 0;
}//main
You should either use unique names, or you can use the indexed ("array") style of construction.
See the documentation for the Object construction function family:
//!Allocates and constructs an array of objects of type MyType (throwing version)
//!Each object receives the same parameters (par1, par2, ...)
MyType *ptr = managed_memory_segment.construct<MyType>("Name")[count](par1, par2...);
and
//!Tries to find a previously created object. If not present, allocates and
//!constructs an array of objects of type MyType (throwing version). Each object
//!receives the same parameters (par1, par2, ...)
MyType *ptr = managed_memory_segment.find_or_construct<MyType>("Name")[count](par1, par2...);
and
//!Allocates and constructs an array of objects of type MyType (throwing version)
//!Each object receives parameters returned with the expression (*it1++, *it2++,... )
MyType *ptr = managed_memory_segment.construct_it<MyType>("Name")[count](it1, it2...);
and possibly some more. Look for [count].
(I recommend using unique names for simplicity)
Update
To the comments, here's what I meant with "unique name". I've tested it, and itworks fine:
Live1 On Coliru
#include <boost/interprocess/containers/vector.hpp>
#include <boost/interprocess/containers/list.hpp>
#include <boost/interprocess/managed_shared_memory.hpp>
#include <cassert>
typedef boost::interprocess::allocator<int, boost::interprocess::managed_shared_memory::segment_manager>
ShmemAllocator; // Define an STL compatible allocator of ints that allocates from the managed_shared_memory. This allocator
// will allow placing containers in the segment
typedef boost::interprocess::vector<int, ShmemAllocator> MyVector; // Alias a vector that uses the previous STL-like allocator so
// that allocates its values from the segment
typedef boost::interprocess::allocator<int, boost::interprocess::managed_shared_memory::segment_manager> ShmemListAllocator;
typedef boost::interprocess::list<int, ShmemListAllocator> MyList;
int main()
{
// Construct managed shared memory
std::remove("/dev/shm/MySharedMemory");
boost::interprocess::managed_shared_memory segment(boost::interprocess::create_only, "MySharedMemory", 65536);
// const ShmemAllocator alloc_inst(segment.get_segment_manager());
MyVector *instance = segment.construct<MyVector>("MyType instance 1")(segment.get_segment_manager());
MyVector *instance2 = segment.construct<MyVector>("MyType instance 2")(segment.get_segment_manager());
MyList *instance3 = segment.construct<MyList> ("MyList instance")(segment.get_segment_manager());
assert(instance);
assert(instance2);
assert(instance3);
assert(!std::equal_to<void*>()(instance, instance2));
assert(!std::equal_to<void*>()(instance, instance3));
assert(!std::equal_to<void*>()(instance2, instance3));
}
1 Of course, SHM is not supported on Coliru. However, identical sample using mapped file: Live On Coliru

How to reach struct sk_buff members?

I am trying to modify the source IP of all packets outcoming from the machine to something I specify in this Kernel Module, but everytime I try to access nh.iph->saddr I get an error in compile time that says Struct sk_buff has no member named nh
What am I doing wrong here?
Have I missed some header or something??
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/skbuff.h>
#include <linux/ip.h> /* For IP header */
#include <linux/inet.h> /* For in_aton(); htonl(); and other related Network utility functions */
static struct nf_hook_ops nfho;
unsigned int hook_func(unsigned int hooknum,
struct sk_buff **skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
struct sk_buff *sb = *skb;
struct in_addr masterIP;
masterIP.s_addr = htonl (in_aton("192.168.1.10"));
sb->nh.iph->saddr = masterIP.s_addr;
return NF_ACCEPT;
}
Note that I am running Ubuntu 10.04 LTS 64 bits
Kernel 2.6.32-33
In your kernel version the struct sk_buff has changed. It no longer has those members. To access the ip header you should try:
#include <linux/ip.h>
struct iphdr* iph = ip_hdr(skb);
Then just use the iph variable to change the addresses, something like:
iph->saddr = ....
iph->daddr = ....
Also, don't forget that you might need to recalculate ip and possible transport packets checksums.
You can find the definition of struck sk_buff in 'include/linux/skbuff.h'.
It does not have an nh field, which explains the compilation errors you're seeing. It does have a 'network_header' field, which is probably what you're looking for.

Resources