How to get parent process ID using objective c in OS X? - objective-c

I have PID of some process and need to get parent process id. How to get it using objective c?

Original source: http://www.objectpark.net/parentpid.html
#include <sys/sysctl.h>
#define OPProcessValueUnknown UINT_MAX
int ProcessIDForParentOfProcessID(int pid)
{
struct kinfo_proc info;
size_t length = sizeof(struct kinfo_proc);
int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, pid };
if (sysctl(mib, 4, &info, &length, NULL, 0) < 0)
return OPProcessValueUnknown;
if (length == 0)
return OPProcessValueUnknown;
return info.kp_eproc.e_ppid;
}

Related

GNU Radio circular buffer manipulation

I encountered the following error
gr::log :WARN: tpb_thread_body - asynchronous message buffer overflowing, dropping message
Out of serendipity, I ran into this GNU Radio presentation on
Youtube.
The presenter mentioned an OOT block he called "buffer" that is capable of eliminating the "buffer overflowing" error. Apparently, this block plays with different sample rates and the so-called "circular buffers". I haven't worked with circular buffers myself. Any ideas on circular buffers or any hints on how to build this buffer block are welcome.
EDIT
Below is the flowgraph that generates the error. As it was suggested in the comments, the culprits could be the message processing blocks (red-circled) namely generateCADU (for generating standard CCSDS frames) and processCADU (for extracting CADUs from a data stream).
The implementation file of the generateCADU block is given below
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gnuradio/io_signature.h>
#include "generateCADU_impl.h"
#include "fec/ReedSolomon/ReedSolomon.h"
#include "fec/Scrambler/Scrambler.h"
namespace gr {
namespace ccsds {
generateCADU::sptr
generateCADU::make(int frameLength,std::string sync, int scramble, int rs, int intDepth)
{
return gnuradio::get_initial_sptr
(new generateCADU_impl(frameLength, sync, scramble, rs, intDepth));
}
/*
* The private constructor
*/
generateCADU_impl::generateCADU_impl(int frameLength,std::string sync, int scramble, int rs, int intDepth)
: gr::sync_block("generateCADU",
gr::io_signature::make(1, 1, sizeof(unsigned char)),
gr::io_signature::make(0, 0, 0)),
d_frameLength(frameLength),d_scramble(scramble == 1),d_rs(rs >= 1), d_basis(rs >= 2), d_intDepth(intDepth)
{
set_output_multiple(d_frameLength);
//Registering output port
message_port_register_out(pmt::mp("out"));
d_sync = parse_string(sync);
}
/*
* Our virtual destructor.
*/
generateCADU_impl::~generateCADU_impl()
{
}
unsigned char
generateCADU_impl::parse_hex(char c)
{
if ('0' <= c && c <= '9') return c - '0';
if ('A' <= c && c <= 'F') return c - 'A' + 10;
if ('a' <= c && c <= 'f') return c - 'a' + 10;
std::abort();
}
std::vector<unsigned char>
generateCADU_impl::parse_string(const std::string & s)
{
if (s.size() % 2 != 0) std::abort();
std::vector<unsigned char> result(s.size() / 2);
for (std::size_t i = 0; i != s.size() / 2; ++i)
result[i] = 16 * parse_hex(s[2 * i]) + parse_hex(s[2 * i + 1]);
return result;
}
int
generateCADU_impl::work(int noutput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items)
{
const unsigned char *in = (const unsigned char *) input_items[0];
//Reed-Solomon and Scrambler objects
ReedSolomon RS(16,d_intDepth,d_basis);// False = conventional, True = dual-basis
Scrambler S;
//Buffers
unsigned char *frameBuffer1 = (unsigned char*)malloc(d_frameLength*sizeof(unsigned char));
std::vector<unsigned char> frameBuffer2;
//The work function engine
for(int i = 0; (i + d_frameLength) < noutput_items; i += d_frameLength)
{
//Copying data from input stream
memcpy(frameBuffer1,in + i + d_frameLength,d_frameLength);
//Copying frame into std::vector buffer
frameBuffer2.insert(frameBuffer2.begin(),frameBuffer1, frameBuffer1 + d_frameLength);
//Optional scrambling and Reed-Solomon
if (d_rs) RS.Encode_RS(frameBuffer2);
if (d_scramble) S.Scramble(frameBuffer2);
//Insert sync word
frameBuffer2.insert(frameBuffer2.begin(), d_sync.begin(), d_sync.end());
//Transmitting PDU
pmt::pmt_t pdu(pmt::cons(pmt::PMT_NIL,pmt::make_blob(frameBuffer2.data(),frameBuffer2.size())));
message_port_pub(pmt::mp("out"), pdu);
//Clear buffer
frameBuffer2.clear();
}
// Tell runtime system how many output items we produced.
return noutput_items;
}
} /* namespace ccsds */
} /* namespace gr */
And here is the processCADU block. This block uses tags generated by the synchronizeCADU (which is simply a wrapper for the correlate_access_tag block) to extract CADUs
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gnuradio/io_signature.h>
#include "processCADU_impl.h"
#include "fec/ReedSolomon/ReedSolomon.h"
#include "fec/Scrambler/Scrambler.h"
namespace gr {
namespace ccsds {
processCADU::sptr
processCADU::make(int frameLength, int scramble, int rs, int intDepth, std::string tagName)
{
return gnuradio::get_initial_sptr
(new processCADU_impl(frameLength, scramble, rs, intDepth, tagName));
}
/*
* The private constructor
*/
processCADU_impl::processCADU_impl(int frameLength, int scramble, int rs, int intDepth, std::string tagName)
: gr::sync_block("processCADU",
gr::io_signature::make(1, 1, sizeof(unsigned char)),
gr::io_signature::make(0, 0, 0)),
d_frameLength(frameLength),d_scramble(scramble == 1),d_rs(rs >= 1), d_basis(rs >= 2), d_intDepth(intDepth)
{
//Multiple input
set_output_multiple(d_frameLength * 8);
//Registering output port
message_port_register_out(pmt::mp("out"));
if (d_rs) d_frameLength += 32 * d_intDepth;
//SEtting tag name
key = pmt::mp(tagName);
}
/*
* Our virtual destructor.
*/
processCADU_impl::~processCADU_impl()
{
delete d_pack;
}
int
processCADU_impl::work(int noutput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items)
{
const unsigned char *in = (const unsigned char *) input_items[0];
unsigned char *out = (unsigned char *) output_items[0];
void *msg_data = NULL;
unsigned char frame_data[d_frameLength];
unsigned char frame_len = 0;
std::vector<unsigned char> frameBuffer;
//Reed-Solomon and Scrambler objects
ReedSolomon RS(16,d_intDepth,d_basis);// False = conventional, True = dual-basis
std::vector<int> errors;//errors.push_back(0);
Scrambler S;
d_tags.clear();
d_pack = new blocks::kernel::pack_k_bits(8);
this->get_tags_in_window(d_tags, 0, 0, noutput_items,key);
for(d_tags_itr = d_tags.begin(); d_tags_itr != d_tags.end(); d_tags_itr++) {
// Check that we have enough data for a full frame
if ((d_tags_itr->offset - this->nitems_read(0)) > (noutput_items - (d_frameLength) * 8))
{
return (d_tags_itr->offset - this->nitems_read(0) - 1);
}
//Pack bits into bytes
d_pack->pack(frame_data, &in[d_tags_itr->offset - this->nitems_read(0)], d_frameLength);
//Copying frame into std::vector buffer
frameBuffer.insert(frameBuffer.begin(),frame_data, frame_data + d_frameLength);
//Optional scrambling and Reed-Solomon
if (d_scramble) S.Scramble(frameBuffer);
//if (d_rs) RS.Decode_RS(frameBuffer,errors);
//If there is Reed-Solomon decoding
if(d_rs)
{
RS.Decode_RS(frameBuffer,errors);
if (RS.Success(errors)) // Success
{
//std::cout << "Success" << std::endl;
pmt::pmt_t pdu(pmt::cons(pmt::PMT_NIL,pmt::make_blob(frameBuffer.data(),frameBuffer.size())));
message_port_pub(pmt::mp("out"), pdu);
/*for(int i=0; i < errors.size(); i++)
{
//std::cout << "Number of Errors : " << errors.at(i) << std::endl << std::endl;
}*/
}
else // Failure
{
std::cout << "RS failure" << std::endl;
}
}
else{
pmt::pmt_t pdu(pmt::cons(pmt::PMT_NIL,pmt::make_blob(frameBuffer.data(),frameBuffer.size())));
message_port_pub(pmt::mp("out"), pdu);
}
//Clear buffers
frameBuffer.clear();
errors.clear();
}
// Tell runtime system how many output items we produced.
return noutput_items;
}
} /* namespace ccsds */
} /* namespace gr */
Regards,
M
Thanks to #MarcusMüller suggestion, using the tagged_stream paradigma as opposed to PDUs solved the problem. I was able to transmit 47 terabytes of data without any problems. Below is the code for the newly implemented block.
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gnuradio/io_signature.h>
#include "genCADU_impl.h"
namespace gr {
namespace ccsds {
genCADU::sptr
genCADU::make(int frameLength,std::string sync, int scramble, int rs, int intDepth, std::string len_tag_key)
{
return gnuradio::get_initial_sptr
(new genCADU_impl(frameLength, sync, scramble, rs, intDepth, len_tag_key));
}
/*
* The private constructor
*/
genCADU_impl::genCADU_impl(int frameLength,std::string sync, int scramble, int rs, int intDepth, std::string len_tag_key)
: gr::tagged_stream_block("genCADU",
gr::io_signature::make(1, 1, sizeof(unsigned char)),
gr::io_signature::make(1, 1, sizeof(unsigned char)),len_tag_key),
d_frameLength(frameLength),d_scramble(scramble == 1),d_rs(rs >= 1), d_basis(rs >= 2), d_intDepth(intDepth)
{
//Synchronization pattern
d_sync = parse_string(sync);
//Reed-Solomon and Scrambler objects
RS = new ReedSolomon(16,d_intDepth,d_basis);// False = conventional, True = dual-basis
S = new Scrambler();
}
/*
* Our virtual destructor.
*/
genCADU_impl::~genCADU_impl()
{
delete RS;
delete S;
}
int
genCADU_impl::calculate_output_stream_length(const gr_vector_int &ninput_items)
{
int noutput_items = (d_rs) ? d_frameLength + 32*d_intDepth + d_sync.size() : d_frameLength + d_sync.size();
return noutput_items ;
}
unsigned char
genCADU_impl::parse_hex(char c)
{
if ('0' <= c && c <= '9') return c - '0';
if ('A' <= c && c <= 'F') return c - 'A' + 10;
if ('a' <= c && c <= 'f') return c - 'a' + 10;
std::abort();
}
std::vector<unsigned char>
genCADU_impl::parse_string(const std::string & s)
{
if (s.size() % 2 != 0) std::abort();
std::vector<unsigned char> result(s.size() / 2);
for (std::size_t i = 0; i != s.size() / 2; ++i)
result[i] = 16 * parse_hex(s[2 * i]) + parse_hex(s[2 * i + 1]);
return result;
}
int
genCADU_impl::work (int noutput_items,
gr_vector_int &ninput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items)
{
const unsigned char *in = (const unsigned char *) input_items[0];
unsigned char *out = (unsigned char *) output_items[0];
int total_len;
//Copy pdu from circular buffer to local buffer
buffer.insert(buffer.end(), in, in + d_frameLength);
//Optional scrambling and Reed-Solomon. TO DO: Turbo and LDPC
if (d_rs) RS->Encode_RS(buffer);
if (d_scramble) S->Scramble(buffer);
//Insert sync word
buffer.insert(buffer.begin(), d_sync.begin(), d_sync.end());
//Copy from local buffer to circular buffer
std::copy(buffer.begin(),buffer.end(),out);
//Clear the local buffer
total_len = buffer.size();
buffer.clear();
// Tell runtime system how many output items we produced.
return total_len;
}
} /* namespace ccsds */
} /* namespace gr */
Regards,
M.

OpenCL Local memory and Xcode

I'm trying to learn OpenCL on a Mac, which appears to have some differences in implementation from the OpenCL book I'm reading. I want to be able to dynamically allocate local memory on the GPU. What I'm reading is I need to use the clSetKernelArg function, but that doesn't work within Xcode 6.4. Here's the code as it stands (never mind it's a pointless program, just trying to learn the syntax for shared memory). In Xcode, the kernel is written as a stand-alone .cl file similar to CUDA, so that's a separate file.
add.cl:
kernel void add(int a, int b, global int* c, local int* d)
{
d[0] = a;
d[1] = b;
*c = d[0] + d[1];
}
main.c:
#include <stdio.h>
#include <OpenCL/opencl.h>
#include "add.cl.h"
int main(int argc, const char * argv[]) {
int a = 3;
int b = 5;
int c;
int* cptr = &c;
dispatch_queue_t queue = gcl_create_dispatch_queue(CL_DEVICE_TYPE_GPU, NULL);
void* dev_c = gcl_malloc(sizeof(cl_int), NULL, CL_MEM_WRITE_ONLY);
// attempt to create local memory buffer
void* dev_d = gcl_malloc(2*sizeof(cl_int), NULL, CL_MEM_READ_WRITE);
// clSetKernelArg(add_kernel, 3, 2*sizeof(cl_int), NULL);
dispatch_sync(queue, ^{
cl_ndrange range = { 1, {0, 0, 0}, {1, 0, 0}, {1, 0, 0} };
// This gives a warning:
// Warning: Incompatible pointer to integer conversion passing 'cl_int *'
// (aka 'int *') to parameter of type 'size_t' (aka 'unsigned long')
add_kernel(&range, a, b, (cl_int*)dev_c, (cl_int*)dev_d);
gcl_memcpy((void*)cptr, dev_c, sizeof(cl_int));
});
printf("%d + %d = %d\n", a, b, c);
gcl_free(dev_c);
dispatch_release(queue);
return 0;
}
I've tried putting clSetKernelArg where indicated and it doesn't like the first argument:
Error: Passing 'void (^)(const cl_ndrange *, cl_int, cl_int, cl_int *, size_t)' to parameter of incompatible type 'cl_kernel' (aka 'struct _cl_kernel *')
I've looked and looked but can't find any examples illustrating this point within the Xcode environment. Can you point me in the right direction?
Managed to solve this by ditching Apple's extensions and using standard OpenCL 1.2 calls. That means replacing gcl_malloc with clCreateBuffer, replacing dispatch_sync with clEnqueueNDRangeKernel, and most importantly, using clSetKernelArg with NULL in the last argument for local variables. Works like a charm.
Here's the new version:
char kernel_add[1024] =
"kernel void add(int a, int b, global int* c, local int* d) \
{\
d[0] = a;\
d[1] = b;\
*c = d[0] + d[1];\
}";
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <OpenCL/opencl.h>
int main(int argc, const char * argv[]) {
int a = 3;
int b = 5;
int c;
cl_device_id device_id;
int err = clGetDeviceIDs(NULL, CL_DEVICE_TYPE_GPU, 1, &device_id, NULL);
cl_context context = clCreateContext(0, 1, &device_id, NULL, NULL, &err);
cl_command_queue queue = clCreateCommandQueue(context, device_id, 0, &err);
const char* srccode = kernel;
cl_program program = clCreateProgramWithSource(context, 1, &srccode, NULL, &err);
err = clBuildProgram(program, 0, NULL, NULL, NULL, NULL);
cl_kernel kernel = clCreateKernel(program, "kernel_add", &err);
cl_mem dev_c = clCreateBuffer(context, CL_MEM_WRITE_ONLY, sizeof(int), NULL, NULL);
err = clSetKernelArg(kernel, 0, sizeof(int), &a);
err |= clSetKernelArg(kernel, 1, sizeof(int), &b);
err |= clSetKernelArg(kernel, 2, sizeof(cl_mem), &dev_c);
err |= clSetKernelArg(kernel, 3, sizeof(int), NULL);
size_t one = 1;
err = clEnqueueNDRangeKernel(queue, kernel, 1, NULL, &one, NULL, 0, NULL, NULL);
clFinish(queue);
err = clEnqueueReadBuffer(queue, dev_c, true, 0, sizeof(int), &c, 0, NULL, NULL);
clReleaseMemObject(dev_c);
clReleaseKernel(kernel);
clReleaseProgram(program);
clReleaseCommandQueue(queue);
clReleaseContext(context);
return 0;
}
In regular OpenCL, for a kernel parameter declared as a local pointer, you don't allocate a host buffer and pass it in (like you're doing with dev_d). Instead you do a clSetKernelArg with the size of the desired local storage but a NULL pointer (like this: clSetKernelArg(kernel, 2, sizeof(cl_int) * local_work_size[0], NULL)). You'll have to translate that into the Xcode way if you insist on being platform-specific.

CUDA Thrust sort_by_key when the key is a tuple dealt with by zip_iterator's with custom comparison predicate

I've looked through a lot of questions here for something similar and there are quite a few, albeit with one minor change. I'm trying to sort values with a zip_iterator as a compound key.
Specifically, I have the following function:
void thrustSort(
unsigned int * primaryKey,
float * secondaryKey,
unsigned int * values,
unsigned int numberOfPoints)
{
thrust::device_ptr dev_ptr_pkey = thrust::device_pointer_cast(primaryKey);
thrust::device_ptr dev_ptr_skey = thrust::device_pointer_cast(secondaryKey);
thrust::device_ptr dev_ptr_values = thrust::device_pointer_cast(values);
thrust::tuple,thrust::device_ptr> keytup_begin =
thrust::make_tuple,thrust::device_ptr>(dev_ptr_pkey, dev_ptr_skey);
thrust::zip_iterator, thrust::device_ptr > > first =
thrust::make_zip_iterator, thrust::device_ptr > >(keytup_begin);
thrust::sort_by_key(first, first + numberOfPoints, dev_ptr_values, ZipComparator());
}
and this custom predicate:
typedef thrust::device_ptr<unsigned int> tdp_uint ;
typedef thrust::device_ptr<float> tdp_float ;
typedef thrust::tuple<tdp_uint, tdp_float> tdp_uif_tuple ;
struct ZipComparator
{
__host__ __device__
inline bool operator() (const tdp_uif_tuple &a, const tdp_uif_tuple &b)
{
if(a.head < b.head) return true;
if(a.head == b.head) return a.tail < b.tail;
return false;
}
};
The errors I'm getting are:
Error 1 error : no instance of constructor "thrust::device_ptr::device_ptr [with T=unsigned int]" matches the argument list C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v4.0\include\thrust\detail\tuple.inl 309 1 ---
Error 2 error : no instance of constructor "thrust::device_ptr::device_ptr [with T=float]" matches the argument list C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v4.0\include\thrust\detail\tuple.inl 401 1 ---
Any ideas what might cause this / how do I write a predicate that indeed works?
Thanks in Advance,
Nathan
The comparator takes arguments of type const thrust::tuple<unsigned int, float>&. The const tdp_uif_tuple& type you defined expands to const thrust::tuple<thrust::device_ptr<unsigned int>, thrust:device_ptr<float> >&
The code below compiles for me:
struct ZipComparator
{
__host__ __device__
inline bool operator() (const thrust::tuple<unsigned int, float> &a, const thrust::tuple<unsigned int, float> &b)
{
if(a.head < b.head) return true;
if(a.head == b.head) return a.tail < b.tail;
return false;
}
};
Hope it does for you as well :)
http://code.google.com/p/thrust/wiki/QuickStartGuide#zip_iterator has more details on the zip iterator.
Not required, but if you're looking to clean up the length of those templates, you can do this:
void thrustSort(
unsigned int * primaryKey,
float * secondaryKey,
unsigned int * values,
unsigned int numberOfPoints)
{
tdp_uint dev_ptr_pkey(primaryKey);
tdp_float dev_ptr_skey(secondaryKey);
tdp_uint dev_ptr_values(values);
thrust::tuple<tdp_uint, tdp_float> keytup_begin = thrust::make_tuple(dev_ptr_pkey, dev_ptr_skey);
thrust::zip_iterator<thrust::tuple<tdp_uint, tdp_float> > first =
thrust::make_zip_iterator(keytup_begin);
thrust::sort_by_key(first, first + numberOfPoints, dev_ptr_values, ZipComparator());
}
A lot of the template arguments can be inferred from the arguments.
This is a fully worked example on how using sort_by_key when the key is a tuple dealt with by zip_iterator's and a customized comparison operator.
#include <thrust/device_vector.h>
#include <thrust/sort.h>
#include "Utilities.cuh"
// --- Defining tuple type
typedef thrust::tuple<int, int> Tuple;
/**************************/
/* TUPLE ORDERING FUNCTOR */
/**************************/
struct TupleComp
{
__host__ __device__ bool operator()(const Tuple& t1, const Tuple& t2)
{
if (t1.get<0>() < t2.get<0>())
return true;
if (t1.get<0>() > t2.get<0>())
return false;
return t1.get<1>() < t2.get<1>();
}
};
/********/
/* MAIN */
/********/
int main()
{
const int N = 8;
// --- Keys and values on the host: allocation and definition
int h_keys1[N] = { 1, 3, 3, 3, 2, 3, 2, 1 };
int h_keys2[N] = { 1, 5, 3, 8, 2, 8, 1, 1 };
float h_values[N] = { 0.3, 5.1, 3.2, -0.08, 2.1, 5.2, 1.1, 0.01};
printf("\n\n");
printf("Original\n");
for (int i = 0; i < N; i++) {
printf("%i %i %f\n", h_keys1[i], h_keys2[i], h_values[i]);
}
// --- Keys and values on the device: allocation
int *d_keys1; gpuErrchk(cudaMalloc(&d_keys1, N * sizeof(int)));
int *d_keys2; gpuErrchk(cudaMalloc(&d_keys2, N * sizeof(int)));
float *d_values; gpuErrchk(cudaMalloc(&d_values, N * sizeof(float)));
// --- Keys and values: host -> device
gpuErrchk(cudaMemcpy(d_keys1, h_keys1, N * sizeof(int), cudaMemcpyHostToDevice));
gpuErrchk(cudaMemcpy(d_keys2, h_keys2, N * sizeof(int), cudaMemcpyHostToDevice));
gpuErrchk(cudaMemcpy(d_values, h_values, N * sizeof(float), cudaMemcpyHostToDevice));
// --- From raw pointers to device_ptr
thrust::device_ptr<int> dev_ptr_keys1 = thrust::device_pointer_cast(d_keys1);
thrust::device_ptr<int> dev_ptr_keys2 = thrust::device_pointer_cast(d_keys2);
thrust::device_ptr<float> dev_ptr_values = thrust::device_pointer_cast(d_values);
// --- Declare outputs
thrust::device_vector<float> d_values_output(N);
thrust::device_vector<Tuple> d_keys_output(N);
auto begin_keys = thrust::make_zip_iterator(thrust::make_tuple(dev_ptr_keys1, dev_ptr_keys2));
auto end_keys = thrust::make_zip_iterator(thrust::make_tuple(dev_ptr_keys1 + N, dev_ptr_keys2 + N));
thrust::sort_by_key(begin_keys, end_keys, dev_ptr_values, TupleComp());
int *h_keys1_output = (int *)malloc(N * sizeof(int));
int *h_keys2_output = (int *)malloc(N * sizeof(int));
float *h_values_output = (float *)malloc(N * sizeof(float));
gpuErrchk(cudaMemcpy(h_keys1_output, d_keys1, N * sizeof(int), cudaMemcpyDeviceToHost));
gpuErrchk(cudaMemcpy(h_keys2_output, d_keys2, N * sizeof(int), cudaMemcpyDeviceToHost));
gpuErrchk(cudaMemcpy(h_values_output, d_values, N * sizeof(float), cudaMemcpyDeviceToHost));
printf("\n\n");
printf("Ordered\n");
for (int i = 0; i < N; i++) {
printf("%i %i %f\n", h_keys1_output[i], h_keys2_output[i], h_values_output[i]);
}
}

USB applications using libusb library

I want to use libusb library for writing some test applications for USB.
Can any one please suggest how to set control transfers using usb_control_msg call?
I am getting bad descriptor error while running the following code.
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "usb.h"
static int vendor_id;
static int product_id;
typedef struct{
int requesttype;
int request;
int value;
int index;
char *bytes;
int size;
int timeout;
}ctrlmsg_param;
void print_endpoint(struct usb_endpoint_descriptor *endpoint)
{
printf("=====End point Information====\n");
printf("bEndpointAddress: %x\n", endpoint->bEndpointAddress);
printf("bmAttributes: %x\n", endpoint->bmAttributes);
printf("wMaxPacketSize: %d\n", endpoint->wMaxPacketSize);
printf("bInterval: %d\n", endpoint->bInterval);
printf("bRefresh: %d\n", endpoint->bRefresh);
printf("bSynchAddress: %d\n", endpoint->bSynchAddress);
}
void print_altsetting(struct usb_interface_descriptor *interface)
{
int i;
printf("\n=====Alternate Setting Information====\n");
printf("bInterfaceNumber: %d\n", interface->bInterfaceNumber);
printf("bAlternateSetting: %d\n", interface->bAlternateSetting);
printf("bNumEndpoints: %d\n", interface->bNumEndpoints);
printf("bInterfaceClass: %d\n", interface->bInterfaceClass);
printf("bInterfaceSubClass: %d\n", interface->bInterfaceSubClass);
printf("bInterfaceProtocol: %d\n", interface->bInterfaceProtocol);
printf("iInterface: %d\n", interface->iInterface);
for (i = 0; i < interface->bNumEndpoints; i++)
print_endpoint(&interface->endpoint[i]);
}
void print_interface(struct usb_interface *interface)
{
int i;
for (i = 0; i < interface->num_altsetting; i++)
print_altsetting(&interface->altsetting[i]);
}
void print_configuration(struct usb_config_descriptor *config)
{
int i;
printf("=====Configuration Information====\n");
printf("wTotalLength: %d\n", config->wTotalLength);
printf("bNumInterfaces: %d\n", config->bNumInterfaces);
printf("bConfigurationValue: %d\n", config->bConfigurationValue);
printf("iConfiguration: %d\n", config->iConfiguration);
printf("bmAttributes: %x\n", config->bmAttributes);
printf("MaxPower: %d\n", config->MaxPower);
for (i = 0; i < config->bNumInterfaces; i++)
print_interface(&config->interface[i]);
}
int print_device(struct usb_device *dev)
{
usb_dev_handle *udev;
char str[100];
int ret, i;
udev = usb_open(dev);
if (udev) {
if (dev->descriptor.iManufacturer) {
ret = usb_get_string_simple(udev, dev->descriptor.iManufacturer, str, sizeof(str));
if (ret > 0)
{
printf("Manufacturer is %s\n",str);
}
}
if (dev->descriptor.iProduct) {
ret = usb_get_string_simple(udev, dev->descriptor.iProduct, str, sizeof(str));
if (ret > 0)
{
printf("Product is %s\n",str);
}
}
}
if (udev)
usb_close(udev);
printf("Possible configurations are %x\n",dev->descriptor.bNumConfigurations);
sleep(2);
for (i = 0; i < dev->descriptor.bNumConfigurations; i++)
print_configuration(&dev->config[i]);
return 0;
}
int htod( const char* str )
{
int decimal;
sscanf( str, "%x", &decimal);
return decimal;
}
void set_data(struct usb_device *dev)
{
ctrlmsg_param param;
param.requesttype= 0;
param.request=0;
param.value=0;
param.index=0;
param.bytes=10;
param.size=0;
param.timeout=5000;
usb_control_msg(dev, param.requesttype, param.request, param.value, param.index, param.bytes, param.size, param.timeout);
printf("error is %s\n",strerror(errno));
return;
}
int main(int argc, char *argv[])
{
struct usb_bus *bus;
struct usb_device *dev;
if(argc != 3)
{
printf("Error in number of arguments\n");
printf("Usage:./usb_info <vendor id> <product id>\n");
exit(0);
}
vendor_id=htod(argv[1]);
product_id=htod(argv[2]);
printf("initializing USB library\n");
usb_init();
printf("Finding Buses and Devices\n");
usb_find_busses();
usb_find_devices();
for (bus = usb_get_busses(); bus; bus = bus->next) {
for (dev = bus->devices; dev; dev = dev->next) {
if ((dev->descriptor.idProduct == product_id) && (dev->descriptor.idVendor == vendor_id)){
printf("Found device with produxt id %x and vendor id %x\n",product_id,vendor_id);
print_device(dev);
set_data(dev);
print_device(dev);
}
}
}
return 0;
}
Regards,
Sandeep
I think that you mean usb_control_msg() is returns an error code for "bad descriptor". Please clarify if this is incorrect.
USB control transfers have some very specific formatting rules, and if the packet you are forming is sent to any compliant device, it will return a request error / stall on the bus.
You are sending the control transfer:
bmRequestType = 0x00
bRequest = 0x00
wValue = 0x0000
wIndex = 0x0000
wSize = 0x0000
this should be interpreted by the USB device as a GET_STATUS request, so wLength is required to be 2, and bmRequestType needs to have the top bit set, indicating this is an IN direction request (from the host's point of view). This is all from Chapter 9 of the USB specification 1.1/2.0/3.1 available at www.usb.org.
The parameter char *bytes (your param.bytes) also needs to be an address/pointer in the call you are making.
A good standard control transfer to test with would be:
bmRequestType = 0x80
bRequest = 0x06
wValue = 0x0001
wIndex = 0x0000
wSize = 0x0008
This request will return the first 8 bytes of the Device Descriptor, it is valid for every USB device, in all states.
The other transfer types (bulk, interrupt) don't have these strict formatting rules, and can be an easier place to start. I'd imagine you have already moved past this issue, since the question has been posted for quite a while, but maybe this response will still help someone else.

True non-blocking two-way communication between parent and external child process

I have read around 50 posts and tutorials on this topic, I have copied, written and tested around 20 alternatives and done every possible research I can think of. Still, I have not seen a working solution for the following problem:
Parent process A wants to pass data to an external process B, let process B modify the data and pass it back to parent process A, then continue with parent process A. Process B is part of an external program suite that I have no influence over, and that is normally run like this on the UNIX command line:
< input_data program_B1 | program_B2 | program_B3 > output_data
...where
input_data, output_data: Some data that is processed in programs B1-B3
program_B1,B2,B3: Programs that read data from stdin (fread) and output to stdout (fwrite) and apply some processing to the data.
So, in sequence:
(1) Parent process A passes data to child process B
(2) Child process B reads data and modifies it
(3) Child process B passes data back to parent process A
(4) Parent process A reads data and continues (for example passing it further on to a process B2..).
(5) Parent process A passes another data set to child process B etc.
The problem is, whatever I do, the program almost always ends up hanging on a read/fread (or write/fwrite?) to or from a pipe.
One important thing to note is that the parent process cannot simply close the pipes after passing data on to the child process, because it works in a loop and wants to pass another set of data to the child process once it has finished processing the first set.
Here is a working set of parent/child programs (compile with g++ pipe_parent.cc -o pipe_parent, g++ pipe_child.cc -o pipe_child) illustrating the problem with unnamed pipes. I have also tried named pipes, but not as extensively. Each execution can have a slightly different outcome. If the sleep statement is omitted in the parent, or the fflush() statement is omitted in the child, the pipes will almost surely block. If the amount of data to be passed on is increased, it will always block independent of the sleep or fflush.
Parent program A:
#include <cstring>
#include <cstdio>
#include <cstdlib>
extern "C" {
#include <unistd.h>
#include <fcntl.h>
}
using namespace std;
/*
* Parent-child inter-communication
* Child is external process
*/
int main() {
int fd[2];
if( pipe(fd) == -1 ) {
fprintf(stderr,"Unable to create pipe\n");
}
int fd_parentWrite = fd[1];
int fd_childRead = fd[0];
if( pipe(fd) == -1 ) {
fprintf(stderr,"Unable to create pipe\n");
exit(-1);
}
int fd_childWrite = fd[1];
int fd_parentRead = fd[0];
pid_t pid = fork();
if( pid == -1 ) {
fprintf(stderr,"Unable to fork new process\n");
exit(-1);
}
if( pid == 0 ) { // Child process
dup2( fd_childRead, fileno(stdin) ); // Redirect standard input(0) to child 'read pipe'
dup2( fd_childWrite, fileno(stdout) ); // Redirect standard output(1) to child 'write pipe'
close(fd_parentRead);
close(fd_parentWrite);
close(fd_childRead);
close(fd_childWrite);
// execl replaces child process with an external one
int ret = execl("/disk/sources/pipe_test/pipe_child","pipe_child",NULL);
fprintf(stderr,"External process failed, return code: %d...\n", ret);
exit(-1);
// Child process is done. Will not continue from here on
}
else { // Parent process
// Nothing to set up
}
// ...more code...
if( pid > 0 ) { // Parent process (redundant if statement)
int numElements = 10000;
int totalSize = numElements * sizeof(float);
float* buffer = new float[numElements];
for( int i = 0; i < numElements; i++ ) {
buffer[i] = (float)i;
}
for( int iter = 0; iter < 5; iter++ ) {
fprintf(stderr,"--------- Iteration #%d -----------\n", iter);
int sizeWrite = (int)write( fd_parentWrite, buffer, totalSize );
if( sizeWrite == -1 ) {
fprintf(stderr,"Parent process write error\n");
exit(-1);
}
fprintf(stderr,"Parent #%d: Wrote %d elements. Total size: %d\n", iter, sizeWrite, totalSize);
sleep(1); // <--- CHANGE!
int sizeRead = (int)read( fd_parentRead, buffer, totalSize );
if( sizeRead <= 0 ) {
fprintf(stderr,"Parent process read error\n");
}
while( sizeRead < totalSize ) {
fprintf(stderr,"Parent #%d: Read %d elements, continue reading...\n", iter, sizeRead);
int sizeNew = (int)read( fd_parentRead, &buffer[sizeRead], totalSize-sizeRead );
fprintf(stderr," ...newly read %d elements\n", sizeNew);
if( sizeNew < 0 ) {
exit(-1);
}
sizeRead += sizeNew;
}
fprintf(stderr,"Parent #%d: Read %d elements. Total size: %d\n", iter, sizeRead, totalSize);
fprintf(stderr,"Examples : %f %f %f\n", buffer[0], buffer[10], buffer[100]);
}
delete [] buffer;
}
close(fd_parentRead);
close(fd_parentWrite);
close(fd_childRead);
close(fd_childWrite);
return 0;
}
Child program B:
#include <cstdio>
using namespace std;
int main() {
int numElements = 10000;
int totalSize = numElements * sizeof(float);
float* buffer = new float[numElements];
int counter = 0;
int sizeRead = 0;
do {
sizeRead = fread( buffer, 1, totalSize, stdin);
fprintf(stderr,"Child #%d: Read %d elements, buffer100: %f\n", counter, sizeRead, buffer[100]);
if( sizeRead > 0 ) {
for( int i = 0; i < numElements; i++ ) {
buffer[i] += numElements;
}
int sizeWrite = fwrite( buffer, 1, totalSize, stdout);
fflush(stdout); // <--- CHANGE!
fprintf(stderr,"Child #%d: Wrote %d elements\n", counter, sizeWrite);
counter += 1;
}
} while( sizeRead > 0 );
return 0;
}
Is there any way to check when the pipe has enough data to be read? Or is there an alternative way to resolve the above problem, with or without pipes?
Please help!
Possibly the best solution when reading is to check with select whether you can read from the pipe. You can even pass a timeout. The alternative might be setting the O_NONBLOCK flag on file descriptor 0 (stdin) with fcntl, though I think the select way is better.
As with ensuring non-blocking write: that's a bit harder as you don't know how much you can write before the pipe blocks. One way (that I feel is very ugly) would be to only write 1 byte chunks and again check with select whether you can write. But that would be a performance killer, so use only if performance in communication is not an issue.
The first answer (using select to find out whether a pipe is ready to be read from) was good but didn't really solve my issue, see also my previous comments. Sooner or later I always ended up with a "race condition" where the program kept hanging either on a read or write.
The solution (maybe not be the only one?) is to run the child-to-parent data transfer in a different thread. I also went back and implemented the pipes as named pipes. It would probably also work with unnamed pipes but I didn't check that.
The final code is below. Note that no explicit flushing is required; the parent-to-child and child-to-parent data transfers are now decoupled. Any comments how this can be improved welcome! One residual problem I can see is that the pipes may fill up depending on how long time the child needs to process the data. I'm not sure how likely this is to happen. And by the way this worked fine with my external programs, not only with the provided child program.
Parent program A:
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <string>
#include <iostream>
extern "C" {
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
#include <signal.h>
#include <sys/wait.h>
#include <pthread.h>
}
using namespace std;
static int const READING = -1;
static int const BUFFER_READY = 1;
static int const FINISHED = 0;
/*
* Parent-child inter-communication
* Child is external process
*/
struct threadStruct {
FILE* file_c2p;
int sizeBuffer;
float* buffer;
int io_flag;
};
// Custom sleep function
void mini_sleep( int millisec ) {
struct timespec req={0},rem={0};
time_t sec = (int)(millisec/1000);
millisec = (int)(millisec-(sec*1000));
req.tv_sec = sec;
req.tv_nsec = millisec*1000000L;
nanosleep(&req,&rem);
}
// Function to be executed within separate thread: Reads in data from file pointer
// Hand-shaking with main thread is done via the flag 'io_flag'
void *threadFunction( void *arg ) {
threadStruct* ptr = (threadStruct*)arg;
ptr->io_flag = READING;
while( ptr->io_flag != FINISHED ) {
if( ptr->io_flag == READING ) {
int sizeRead = fread( ptr->buffer, 1, ptr->sizeBuffer, ptr->file_c2p );
if( sizeRead <= 0 ) {
ptr->io_flag = FINISHED;
return NULL;
}
ptr->io_flag = BUFFER_READY;
}
else {
mini_sleep(10);
}
}
return NULL;
}
//--------------------------------------------------
int main() {
std::string filename_p2c("/tmp/fifo11_p2c");
std::string filename_c2p("/tmp/fifo11_c2p");
fprintf(stderr,"..started\n");
int status = mknod(filename_p2c.c_str(), S_IRUSR | S_IWUSR | S_IFIFO, 0);
if( (status == -1) && (errno != EEXIST) ) {
fprintf(stderr,"Error creating named pipe: %s\n", strerror(errno));
exit(-1);
}
status = mknod(filename_c2p.c_str(), S_IRUSR | S_IWUSR | S_IFIFO, 0);
if( (status == -1) && (errno != EEXIST) ) {
fprintf(stderr,"Error creating named pipe: %s\n", strerror(errno));
exit(-1);
}
FILE* file_dump = fopen("parent_dump","w");
int fd_p2c;
int fd_c2p;
FILE* file_c2p = NULL;
//--------------------------------------------------
// Set up parent/child processes
//
pid_t pid = fork();
if( pid == -1 ) {
fprintf(stderr,"Unable to fork new process\n");
}
if( pid == 0 ) { // Child process
fd_p2c = open( filename_p2c.c_str(), O_RDONLY );
if( fd_p2c < 0 ) {
fprintf(stderr,"Child: Error opening the named pipe: %d %d '%s'\n", fd_p2c, errno, strerror(errno));
exit(-1);
}
fd_c2p = open( filename_c2p.c_str(), O_WRONLY );
if( fd_c2p < 0 ) {
fprintf(stderr,"Child: Error opening the named pipe: %d %d '%s'\n", fd_c2p, errno, strerror(errno));
exit(-1);
}
dup2(fd_p2c,fileno(stdin)); // Redirect standard input(0) to child 'read pipe'
dup2(fd_c2p,fileno(stdout)); // Redirect standard output(1) to child 'write pipe'
close(fd_p2c);
close(fd_c2p);
int ret = execl("/disk/sources/pipe_test/pipe_child","pipe_child",NULL);
fprintf(stderr,"External process failed, return code: %d...\n", ret);
kill( getppid(), 9 ); // Kill parent process
exit(-1);
}
else { // Parent process
fd_p2c = open( filename_p2c.c_str(), O_WRONLY );
if( fd_p2c < 0 ) {
fprintf(stderr,"Parent: Error opening the named pipe: %d %d '%s'\n", fd_p2c, errno, strerror(errno));
exit(-1);
}
file_c2p = fopen( filename_c2p.c_str(), "r");
fd_c2p = fileno( file_c2p );
if( fd_c2p < 0 ) {
fprintf(stderr,"Parent: Error opening the named pipe: %d %d '%s'\n", fd_c2p, errno, strerror(errno));
exit(-1);
}
}
int numElements = 10000;
int sizeBuffer = numElements * sizeof(float);
float* bufferIn = new float[numElements];
float* bufferOut = new float[numElements];
for( int i = 0; i < numElements; i++ ) {
bufferIn[i] = 0.0;
}
int numIterations = 5;
int numBytesAll = numElements * sizeof(float) * numIterations;
pthread_t thread;
threadStruct* threadParam = new threadStruct();
threadParam->file_c2p = file_c2p;
threadParam->sizeBuffer = sizeBuffer;
threadParam->buffer = bufferIn;
threadParam->io_flag = READING;
int thread_stat = pthread_create( &thread, NULL, threadFunction, threadParam );
if( thread_stat < 0 ) {
fprintf(stderr,"Error when creating thread\n");
exit(-1);
}
int readCounter = 0;
int numBytesWrite = 0;
int numBytesRead = 0;
for( int iter = 0; iter < numIterations; iter++ ) {
for( int i = 0; i < numElements; i++ ) {
bufferOut[i] = (float)i + iter*numElements*10;
}
int sizeWrite = (int)write( fd_p2c, bufferOut, sizeBuffer );
if( sizeWrite == -1 ) {
fprintf(stderr,"Parent process write error\n");
exit(-1);
}
numBytesWrite += sizeWrite;
fprintf(file_dump,"Parent #%d: Wrote %d/%d bytes.\n", iter, numBytesWrite, numBytesAll);
if( iter == numIterations-1 ) close(fd_p2c); // Closing output pipe makes sure child receives EOF
if( threadParam->io_flag != READING ) {
numBytesRead += sizeBuffer;
fprintf(file_dump,"Parent #%d: Read %d/%d bytes. Examples: %f %f\n",
readCounter, numBytesRead, numBytesAll, bufferIn[1], bufferIn[numElements-1] );
readCounter += 1;
if( threadParam->io_flag != FINISHED ) threadParam->io_flag = READING;
}
}
//********************************************************************************
//
fprintf(file_dump,"------------------------------\n");
while( threadParam->io_flag != FINISHED ) {
if( threadParam->io_flag == BUFFER_READY ) {
numBytesRead += sizeBuffer;
fprintf(file_dump,"Parent #%d: Read %d/%d bytes. Examples: %f %f\n",
readCounter, numBytesRead, numBytesAll, bufferIn[1], bufferIn[numElements-1] );
readCounter += 1;
if( threadParam->io_flag != FINISHED ) threadParam->io_flag = READING;
}
else {
mini_sleep(10);
}
}
// wait for thread to finish before continuing
pthread_join( thread, NULL );
fclose(file_dump);
fclose(file_c2p);
waitpid(pid, &status, 0); // clean up any children
fprintf(stderr,"..finished\n");
delete [] bufferIn;
delete [] bufferOut;
return 0;
}
Child program B:
#include <cstdio>
using namespace std;
int main() {
int numElements = 10000;
int totalSize = numElements * sizeof(float);
float* buffer = new float[numElements];
FILE* file_dump = fopen("child_dump","w");
int counter = 0;
int sizeRead = 0;
do {
sizeRead = fread( buffer, 1, totalSize, stdin);
if( sizeRead > 0 ) {
fprintf(file_dump,"Child #%d: Read %d bytes, examples: %f %f\n", counter, sizeRead, buffer[1], buffer[numElements-1]);
for( int i = 0; i < numElements; i++ ) {
buffer[i] += numElements;
}
int sizeWrite = fwrite( buffer, 1, totalSize, stdout);
fprintf(file_dump,"Child #%d: Wrote %d bytes, examples: %f %f\n", counter, sizeRead, buffer[1], buffer[numElements-1]);
counter += 1;
}
} while( sizeRead > 0 );
fprintf(file_dump,"Child is finished\n");
fclose(file_dump);
fclose(stdout);
return 0;
}