I am writing a program that needs to attach to other processes (which might be created by a previous instance of my program) and watch when they terminate.
If I keep my program running during the lifetime of the processes I created, everything works fine; but if I start a process, kill my program, then restart it, the previously created process would remains in STOPPED state forever (it seems that the ptrace(PTRACE_CONT,...) can not resume it). The code snippet is attached bellow:
static int exitFlag = 0;
static void sighandler (int/* signum */)
{ exitFlag = 1; }
int JsfNode::run (void)
{
/* load jobs */
{
vector <JobInfo2> jobs;
loadStruct <vector <JobInfo2> > (
jobFile (), jobs);
for (unsigned i=0 ; i<jobs.size () ; i++) {
JobInfo2& info = jobs [i];
string name = info.parm.name;
if (m_jobs.find (name) == m_jobs.end ()) {
Job2& job = m_jobs [name];
job.info = info;
/* trace it so that we can wait() it */
switch (info.state) {
case js2Active:
case js2Canceling:
case js2Suspending:
if (ptrace (PTRACE_ATTACH, info.pid, 0, 0))
jdebug ("PTRACE_ATTACH failed for: %d (%s)\n", info.pid,
strerror (errno));
default: break;
}
}
}
}
/* run until we are signaled to stop */
signal (SIGINT, sighandler);
while (!exitFlag)
sleep (1);
/* save jobs */
{
vector <JobInfo2> jobs;
for (map <string, Job2>::iterator it=m_jobs.begin () ;
it!=m_jobs.end () ; it++) {
JobInfo2& info = it->second.info;
ptrace (PTRACE_DETACH, info.pid, NULL, NULL);
jobs.push_back (info);
}
saveStruct <vector <JobInfo2> > (
jobFile (), jobs);
}
return 0;
}
void JsfNode::startJob (Job2 & job)
{
JobParm2 parm = job.info.parm;
jdebug ("starting \"%s\"..\n", parm.name.c_str());
/* get the uid of the run-as user */
uid_t uid = 0; /* run as root if the specified user is invalid */
struct passwd * pwe = getpwnam (parm.user.c_str());
if (pwe != NULL)
uid = pwe->pw_uid;
/* prepare the script file */
string scriptfile = m_workdir+"/"+parm.name+"_scriptfile";
ofstream ofscriptfile (scriptfile.c_str());
ofscriptfile << parm.script;
ofscriptfile.close();
chown (scriptfile.c_str(), uid, uid);
chmod (scriptfile.c_str(), S_IRWXU|S_IRWXG|S_IRWXO);
/* prepare the MPIMACHINEFILE */
string machinefile = m_workdir+"/"+parm.name+"_machinefile";
ofstream ofmachinefile (machinefile.c_str());
for (Resource::iterator it=parm.res.begin () ; it!=parm.res.end () ; it++)
ofmachinefile << *it << ':' << parm.taskPerNode << '\n';
ofmachinefile.close ();
chown (machinefile.c_str(), uid, uid);
chmod (machinefile.c_str(), S_IRWXU|S_IRWXG|S_IRWXO);
/* prepare the redirection channels */
int ipipe [2] = {-1,-1};
int opipe [2] = {-1,-1};
if (parm.redio > 0) {
if (pipe (ipipe) == -1) {
unlink:
unlink (machinefile.c_str());
unlink (scriptfile.c_str());
return; /* do not fail the job, just try later */
}
if (pipe (opipe) == -1) {
close:
close (ipipe [0]);
close (ipipe [1]);
goto unlink;
}
}
/* OK, fork it! -----------------> */
pid_t pid;
if ((pid = fork ()) == -1) {
close (opipe [0]);
close (opipe [1]);
goto close;
}
if (pid == 0) {
/* enable parent-tracing */
ptrace (PTRACE_TRACEME, 0, NULL, NULL);
/* drop the root privilege */
setuid (uid);
/* redirect stdin/stdout */
if (parm.redio) {
if (dup2 (ipipe [0],0)<0 ||
dup2 (opipe [1],1)<0)
exit (errno);
close (ipipe [0]);
close (ipipe [1]);
close (opipe [0]);
close (opipe [1]);
}
/* prepare the arguments/environments */
char * arg[] = {
strdup (scriptfile.c_str()),
strdup (parm.args.c_str()),
NULL /* the required null entry */
};
setenv ("MPIMACHINEFILE", machinefile.c_str(), 1);
setenv ("DISPLAY", parm.headNode.c_str(), 1);
setenv ("JSF_JOBID", parm.name.c_str(), 1);
/* execute it! ------> */
execv (scriptfile.c_str(), arg);
exit (errno);
}
/* redirect stdin/stdout */
if (parm.redio) {
close (ipipe [0]);
close (opipe [1]);
job.redPipe [0] = opipe [0];
job.redPipe [1] = ipipe [1];
}
/* start the nurse thread */
NurseData * nd = new NurseData (this, job);
if (pthread_create (&job.nurseId, NULL, ::_jobnurse, nd) == 0)
job.nurseActive = true;
else delete nd;
job.info.pid = pid;
setJobState (job, js2Active);
return;
}
void JsfNode::monitorJob (Job2 & job)
{
int status;
pid_t pid = waitpid (job.info.pid, &status, WNOHANG);
if (pid < 0) {
if (errno == ECHILD) {
/* the job process has disappeared.. */
job.exitCode = 0;
setJobState (job, js2Finished);
return;
}
} else if (pid == job.info.pid) {
if (WIFEXITED(status)) {
job.exitCode = WEXITSTATUS(status);
setJobState (job, js2Finished);
return;
} else if (WIFSIGNALED(status)) {
setJobState (job, js2Canceled);
return;
} else if (WIFSTOPPED(status)) {
if (ptrace (PTRACE_CONT, pid, NULL, NULL))
jdebug ("PTRACE_CONT failed for: %d (%s)\n", pid, strerror(errno));
}
}
/* ... */
}
Yes, the problem results from multi-threading. if monitorJob() runs in a seperate thread, ptrace(PTRACE_CONT) just fails. After moving it to the main thread (the one that called ptrace(PTRACE_ATTACH)), things go smoothly.
Related
I am developing a TCP client module for Hololens 1st gen with native C++/CX.
I create a packet class which contains 1 x (uint32_t) + 7 x (float)
The server is implemented in the synchronized manner, which streams the packets to the client (Hololens) every frame.
Receiver.h
namespace HoloNet {
public ref class holoATCFrameReceiver sealed
{
public:
holoATCFrameReceiver(
_In_ Windows::Networking::Sockets::StreamSocket^ streamSocket);
Windows::Foundation::IAsyncOperation<TrackerFrame^>^ ReceiveAsync();
private:
Concurrency::task<TrackerFrame^> ReceiveTrackerFrameAsync();
private:
Windows::Networking::Sockets::StreamSocket^ _streamSocket;
Windows::Storage::Streams::DataReader^ _reader;
bool _readInProgress;
};
}
and Receiver.cpp
namespace HoloNet {
holoATCFrameReceiver::holoATCFrameReceiver(
Windows::Networking::Sockets::StreamSocket ^ streamSocket)
: _streamSocket(streamSocket)
{
_readInProgress = false;
// reader
_reader = ref new Windows::Storage::Streams::DataReader(
_streamSocket->InputStream);
_reader->UnicodeEncoding =
Windows::Storage::Streams::UnicodeEncoding::Utf8;
_reader->ByteOrder =
Windows::Storage::Streams::ByteOrder::LittleEndian;
}
Windows::Foundation::IAsyncOperation<TrackerFrame^>^ holoATCFrameReceiver::ReceiveAsync()
{
return concurrency::create_async(
[this]()
{
return ReceiveTrackerFrameAsync();
});
}
Concurrency::task<TrackerFrame^>
holoATCFrameReceiver::ReceiveTrackerFrameAsync()
{
return concurrency::create_task(
_reader->LoadAsync(TrackerFrame::TrackerFrameLength)
).then([this](Concurrency::task<unsigned int> headerBytesLoadedTaskResult)
{
headerBytesLoadedTaskResult.wait();
const size_t frameBytesLoaded = headerBytesLoadedTaskResult.get();
if (TrackerFrame::TrackerFrameLength != frameBytesLoaded)
{
throw ref new Platform::FailureException();
}
_readInProgress = true;
TrackerFrame^ header;
TrackerFrame::Read(
_reader,
&header);
dbg::trace(
L"SensorFrameReceiver::ReceiveAsync: sensor %i: t( %f, %f %f ), q( %f, %f, %f, %f)",
header->sensorID,
header->x,
header->y,
header->z,
header->qw,
header->qx,
header->qy,
header->qz);
_readInProgress = false;
return header;
});
}
}
The error throws at * _reader->LoadAsync(TrackerFrame::TrackerFrameLength) *
The receiver is called in the client class like below:
void holoTcpATCClient::OnReceiveATCframe(TrackerFrame^& header) {
std::lock_guard<std::mutex> guard(_socketMutex);
// check read in process
if (_readInProcess)
{
return;
}
_readInProcess = true;
concurrency::create_task(
_receiver->ReceiveAsync()).then(
[&](concurrency::task<TrackerFrame^> sensorFrameTask)
{
sensorFrameTask.wait();
TrackerFrame^ sensorFrame = sensorFrameTask.get()
header = sensorFrame;
});
_readInProcess = false;
}
_receiver->ReceiveAsync() is the begining of the error.
I wonder whether there is a way to pretend this happens by doing some modification on LoadAsync() of DataReader for StreamSocket under concurrency:: create_task?
Thank you very much for your help in advance!
I want to play local video file in Qt platform using ffmpeg to decode.Everything is OK except that play speed is as twice as normal.
The first thing I think about is that there must be a sampling frequency involved.But to be a new to ffmpeg,I don't know how to fix this problem.
Above is my code to read frame,is anyone can tell me what's wrong with the code ?
void VideoThread::run()
{
m_pInFmtCtx = avformat_alloc_context(); //ini struct
char path[] = "d:/test.mp4";
// open specific file
if(avformat_open_input(&m_pInFmtCtx, *path, NULL, NULL)){
{
qDebug()<<"get rtsp failed";
return;
}
else
{
qDebug()<<"get rtsp success";
}
if(avformat_find_stream_info(m_pInFmtCtx, NULL) < 0)
{
qDebug()<<"could not find stream information";
return;
}
int nVideoIndex = -1;
for(int i = 0; i < m_pInFmtCtx->nb_streams; i++)
{
if(m_pInFmtCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
{
nVideoIndex = i;
break;
}
}
if(nVideoIndex == -1)
{
qDebug()<<"could not find video stream";
return;
}
qDebug("---------------- File Information ---------------");
m_pCodecCtx = m_pInFmtCtx->streams[nVideoIndex]->codec;
m_pCodec = avcodec_find_decoder(m_pCodecCtx->codec_id);
if(!m_pCodec)
{
qDebug()<<"could not find codec";
return;
}
//start Decoder
if (avcodec_open2(m_pCodecCtx, m_pCodec, NULL) < 0) {
qDebug("Could not open codec.\n");
return;
}
//malloc space for stroring frame
m_pFrame = av_frame_alloc();
m_pFrameRGB = av_frame_alloc();
m_pOutBuf = (uint8_t*)av_malloc(avpicture_get_size(AV_PIX_FMT_RGB32, m_pCodecCtx->width, m_pCodecCtx->height));
avpicture_fill((AVPicture*)m_pFrameRGB, m_pOutBuf, AV_PIX_FMT_RGB32, m_pCodecCtx->width, m_pCodecCtx->height);
//for color switch,from YUV to RGB
struct SwsContext *pImgCtx = sws_getContext(m_pCodecCtx->width, m_pCodecCtx->height, m_pCodecCtx->pix_fmt,
m_pCodecCtx->width, m_pCodecCtx->height, AV_PIX_FMT_RGB32, SWS_BICUBIC, NULL, NULL, NULL);
int nSize = m_pCodecCtx->width * m_pCodecCtx->height;
m_pPacket = (AVPacket *)av_malloc(sizeof(AVPacket));
if(av_new_packet(m_pPacket, nSize) != 0)
{
qDebug()<<"new packet failed";
}
//isInterruptionRequested is a flag,determine whether the thread is over
// read each frame from specific video file
while (!isInterruptionRequested())
{
int nGotPic = 0;
if(av_read_frame(m_pInFmtCtx, m_pPacket) >= 0)
{
if(m_pPacket->stream_index == nVideoIndex)
{
//avcodec_decode_video2()transform from packet to frame
if(avcodec_decode_video2(m_pCodecCtx, m_pFrame, &nGotPic, m_pPacket) < 0)
{
qDebug()<<"decode failed";
return;
}
if(nGotPic)
{ // transform to RGB color
sws_scale(pImgCtx, (const uint8_t* const*)m_pFrame->data,
m_pFrame->linesize, 0, m_pCodecCtx->height, m_pFrameRGB->data,
m_pFrameRGB->linesize);
// save to QImage,for later use
QImage *pImage = new QImage((uchar*)m_pOutBuf, m_pCodecCtx->width, m_pCodecCtx->height, QImage::Format_RGB32);
}
}
}
av_free_packet(m_pPacket);
msleep(5);
}
exec();
}
We have created one local cloud instance using KAA 0.10 and generated C Posix SDK after adding some Log Upload Schema.
I have created one sample program in which just create one KAA client and update dummy endpoints and started KAA client in which one dummy callback function will be called which is working fine without any issue.
After that, I have extended my working code to upload Log Data on some events like every 1 seconds or every 5 logs count and executed same code on my Linux System but I am getting "failed_log_delivery_callback" randomly not as per strategy defined.
Please find following code which I am using to check Log Upload Strategy using KAA 0.10 C SDK.
/* Set of routines that handles log delivery events */
static void success_log_delivery_callback(void *context, const kaa_log_bucket_info_t *bucket)
{
printf("+++++++++++++++++ success_log_delivery_callback called +++++++++++++++++++++++\n");
printf("Bucket: %u is successfully delivered. Logs uploaded: %zu\n",
bucket->bucket_id,
bucket->log_count);
}
static void failed_log_delivery_callback(void *context, const kaa_log_bucket_info_t *bucket)
{
printf("+++++++++++++++++ failed_log_delivery_callback called +++++++++++++++++++++++\n");
printf("Log delivery of the bucket: %u is failed!\n", bucket->bucket_id);
}
static void timeout_log_delivery_callback(void *context, const kaa_log_bucket_info_t *bucket)
{
printf("+++++++++++++++++ timeout_log_delivery_callback called +++++++++++++++++++++++\n");
printf("Timeout reached for log delivery of the bucket: %u!\n", bucket->bucket_id);
}
/* Log delivery listener callbacks. Each callback called whenever something happen with a log bucket. */
kaa_log_delivery_listener_t log_listener = {
.on_success = success_log_delivery_callback, /* Called if log delivered successfully */
.on_failed = failed_log_delivery_callback, /* Called if delivery failed */
.on_timeout = timeout_log_delivery_callback, /* Called if timeout occurs */
.ctx = NULL, /* Optional context */
};
kaa_union_t *kaa_logging_union_create(const char *data, uint8_t type, destroy_fn destroy)
{
kaa_union_t *str;
str = kaa_logging_union_string_or_null_branch_0_create();
str->data = kaa_string_move_create(data,NULL);
return str;
}
kaa_union_t *kaa_profile_union_create(const char *data, uint8_t type, destroy_fn destroy)
{
kaa_union_t *str;
str = kaa_logging_union_string_or_null_branch_0_create();
str->data = kaa_string_move_create(data,NULL);
return str;
}
static void dummy_function(void *context)
{
kaa_error_t error_code = 0;
printf("\n\n**************** Hello, I am a Kaa Application!!!!!!!!!!!!!!!!!!!!!!\n\n");
kaa_logging_event_push_t *log_push;
/* Log information. Populated when log is added via kaa_logging_add_record() */
kaa_log_record_info_t log_info;
/* kaa logging event push data will be created from here */
log_push = kaa_logging_event_push_create();
if(log_push == NULL)
{
printf("can not create log data\r\n");
kaa_client_stop(kaa_client);
return;
}
log_push->tag = kaa_logging_union_create("67891",0,NULL);
if(log_push->tag == NULL)
{
printf("can not create log data\r\n");
kaa_client_stop(kaa_client);
return;
}
log_push->rid = kaa_logging_union_create("77:88:99:11:22:33",0,NULL);
if(log_push->rid == NULL)
{
printf("can not create log data\r\n");
kaa_client_stop(kaa_client);
return;
}
log_push->var = kaa_logging_union_create("HIJKLMN",0,NULL);
if(log_push->var == NULL)
{
printf("can not create log data\r\n");
kaa_client_stop(kaa_client);
return;
}
log_push->payload = kaa_string_move_create("Linux System KAA Message",NULL);
if(log_push->payload == NULL)
{
printf("can not create log data\r\n");
kaa_client_stop(kaa_client);
return;
}
/* kaa logging push data will be added from here */
error_code = kaa_logging_add_record(kaa_client_get_context(kaa_client)->log_collector, log_push, &log_info);
if (error_code)
{
printf("Failed to add log record, error code %d\n", error_code);
kaa_client_stop(kaa_client);
return;
}
printf("log message added :: count :: %d\r\n", kaa_log_count);
/* kaa logging push data will be destroyed from here */
log_push->destroy(log_push);
kaa_log_count++;
/* kaa client will be stopped from here */
/*error_code = kaa_client_stop(kaa_client);
if (error_code)
{
printf("kaa_client_stop is failed to execute.....\n");
return;
}
else
printf("kaa_client_stop is executed successfully.....\n"); */
}
int main(void)
{
kaa_error_t error_code = 0;
int i = 0;
void *log_storage_context = NULL, *log_upload_strategy_context = NULL;
printf("*********** kaa_basic_main started **************\n");
kaa_profile_t *profile = NULL;
printf("Before kaa_client_create API...\n");
/* kaa client will be created from here */
error_code = kaa_client_create(&kaa_client, NULL);
if (error_code)
{
printf("kaa_client_create API is failed to execute...\n");
return EXIT_FAILURE;
}
else
printf("kaa_client_create API is called successfully...\n");
sleep(2);
kaa_endpoint_id_p buff = (kaa_endpoint_id_p)malloc(23);
/* kaa profile manager endpoint id comes from here */
error_code = kaa_profile_manager_get_endpoint_id(kaa_client_get_context(kaa_client)->profile_manager,buff);
if (error_code)
{
printf("kaa_profile_manager_get_endpoint_id is failed to execute.....\n");
return EXIT_FAILURE;
}
else
{
for(i = 0; i < 23; i++)
{
printf("kaa_profile_manager_get_endpoint_id[i] :: 0x%x\n", buff[i]);
}
printf("kaa_profile_manager_get_endpoint_id API is called successfully...\n");
}
free(buff);
/* kaa profile will be created from here */
profile = (kaa_profile_t *)kaa_profile_profile_create();
printf("kaa_profile_profile_create API is called...\n");
profile->id = kaa_string_move_create(id,NULL);
profile->key = kaa_string_move_create((const char *)key,NULL);
profile->current_firmware_version = kaa_string_move_create(f_version,NULL);
profile->serial_number = kaa_string_move_create(ser_number,NULL);
profile->health = kaa_string_move_create(health,NULL);
profile->pii = kaa_string_move_create(pii,NULL);
profile->info = kaa_string_move_create(info,NULL);
sleep(2);
printf("before kaa_profile_manager_update_profile API is called...\n");
/* kaa profile will be updated from here */
error_code = kaa_profile_manager_update_profile(kaa_client_get_context(kaa_client)->profile_manager, profile);
if (error_code)
{
printf("kaa_profile_manager_update_profile is failed to execute.....\n");
return EXIT_FAILURE;
}
else
printf("kaa_profile_manager_update_profile API is called successfully...\n");
sleep(2);
printf("before calling kaa_client_start.....\n");
/* The internal memory log storage distributed with Kaa SDK */
error_code = ext_unlimited_log_storage_create(&log_storage_context, kaa_client_get_context(kaa_client)->logger);
if (error_code)
{
printf("ext_unlimited_log_storage_create is failed to execute.....\n");
return EXIT_FAILURE;
}
else
printf("ext_unlimited_log_storage_create is executed successfully.....\n");
/* KAA Upload Strategy will be created with timeout */
error_code = ext_log_upload_strategy_create(kaa_client_get_context(kaa_client), &log_upload_strategy_context, KAA_LOG_UPLOAD_BY_TIMEOUT_STRATEGY);
if (error_code)
{
printf("ext_log_upload_strategy_create is failed to execute.....\n");
return EXIT_FAILURE;
}
else
printf("ext_log_upload_strategy_create is executed successfully.....\n");
/* Strategy will upload logs every 1 seconds. */
error_code = ext_log_upload_strategy_set_upload_timeout(log_upload_strategy_context, 1);
if (error_code)
{
printf("ext_log_upload_strategy_set_threshold_count is failed to execute.....\n");
return EXIT_FAILURE;
}
else
printf("ext_log_upload_strategy_set_threshold_count is executed successfully.....\n");
/* Specify log bucket size constraints */
kaa_log_bucket_constraints_t bucket_sizes = {
.max_bucket_size = 512, /* Bucket size in bytes */
.max_bucket_log_count = 5, /* Maximum log count in one bucket */
};
/* Initialize the log storage and strategy (by default it is not set) */
error_code = kaa_logging_init(kaa_client_get_context(kaa_client)->log_collector
, log_storage_context
, log_upload_strategy_context
, &bucket_sizes);
if (error_code)
{
printf("kaa_logging_init is failed to execute.....\n");
return EXIT_FAILURE;
}
else
printf("kaa_logging_init is executed successfully.....\n");
/* Add listeners to a log collector */
kaa_logging_set_listeners(kaa_client_get_context(kaa_client)->log_collector, &log_listener);
if (error_code)
{
printf("kaa_logging_set_listeners is failed to execute.....\n");
return EXIT_FAILURE;
}
else
printf("kaa_logging_set_listeners is executed successfully.....\n");
/* kaa client will be started from here */
error_code = kaa_client_start(kaa_client, dummy_function, (void *)kaa_client, 0);
if (error_code)
{
printf("kaa_client_start is failed to execute.....\n");
return EXIT_FAILURE;
}
else
printf("kaa_client_start is executed successfully.....\n");
printf("after calling kaa_client_start.....\n");
sleep(2);
/* kaa client will be destroyed from here */
kaa_client_destroy(kaa_client);
printf("after calling kaa_client_destroy.....\n");
return EXIT_SUCCESS;
}
Let me know if need any more details from my-side.
I have been implementing the module to send the bytes in chunks, 20 bytes each onto the MCU device via BLE. When it comes to writing the bytes more than 60 bytes and so on, the last chunk of the bytes ( usually less than 20 bytes) is often missed. Hence, the MCU device cannot get the checksum and write the value. I have modified the call back to Thread.sleep(200) to change it but it sometimes works on writing 61 bytes or sometimes not. Would you please tell me are there any synchronous method to write the bytes in chunks ? The below is my working :
#Override
public void onCharacteristicWrite(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic, int status) {
try {
Thread.sleep(300);
if (status != BluetoothGatt.GATT_SUCCESS) {
disconnect();
return;
}
if(status == BluetoothGatt.GATT_SUCCESS) {
System.out.println("ok");
broadcastUpdate(ACTION_DATA_READ, mReadCharacteristic, status);
}
else {
System.out.println("fail");
broadcastUpdate(ACTION_DATA_WRITE, characteristic, status);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public synchronized boolean writeCharacteristicData(BluetoothGattCharacteristic characteristic ,
byte [] byteResult ) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
return false;
}
boolean status = false;
characteristic.setValue(byteResult);
characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE);
status = mBluetoothGatt.writeCharacteristic(characteristic);
return status;
}
private void sendCommandData(final byte [] commandByte) {
// TODO Auto-generated method stub
if(commandByte.length > 20 ){
final List<byte[]> bytestobeSent = splitInChunks(commandByte);
for(int i = 0 ; i < bytestobeSent.size() ; i ++){
for(int k = 0 ; k < bytestobeSent.get(i).length ; k++){
System.out.println("LumChar bytes : "+ bytestobeSent.get(i)[k] );
}
BluetoothGattService LumService = mBluetoothGatt.getService(A_SERVICE);
if (LumService == null) { return; }
BluetoothGattCharacteristic LumChar = LumService.getCharacteristic(AW_CHARACTERISTIC);
if (LumChar == null) { System.out.println("LumChar"); return; }
//Thread.sleep(500);
writeCharacteristicData(LumChar , bytestobeSent.get(i));
}
}else{
....
You need to wait for the onCharacteristicWrite() callback to be invoked before sending the next write. The typical solution is to make a job queue and pop a job off the queue for each callback you get to onCharacteristicWrite(), onCharacteristicRead(), etc.
In other words, you can't do it in a for loop unfortunately, unless you want to set up some kind of lock that waits for the callback before going on to the next iteration. In my experience a job queue is a cleaner general-purpose solution though.
After some try, it's that I can see :
The extension execution is asynchronous from dart but not C, which is blocking while the current method has not completed.
Dart_NativeFunction ResolveName(Dart_Handle name, int argc);
Dart_Handle HandleError(Dart_Handle handle);
void wrapped_method(Dart_Port dest_port_id, Dart_CObject* message) {
Dart_Port reply_port_id = message->value.as_array.values[0]->value.as_send_port;
printf("Before sleep\n");
sleep(5);
printf("Hello from c !\n");
Dart_CObject result;
result.type = Dart_CObject_kBool;
result.value.as_bool = true;
Dart_PostCObject(reply_port_id, &result);
}
DART_EXPORT Dart_Handle sample_extension_Init(Dart_Handle parent_library) {
if (Dart_IsError(parent_library)) { return parent_library; }
Dart_Handle result_code = Dart_SetNativeResolver(parent_library, ResolveName);
if (Dart_IsError(result_code)) return result_code;
return Dart_Null();
}
void sample_extension_ServicePort(Dart_NativeArguments arguments) {
Dart_EnterScope();
Dart_SetReturnValue(arguments, Dart_Null());
Dart_Port service_port = Dart_NewNativePort("sample_extension_ServicePort", wrapped_method, true);
if (service_port != ILLEGAL_PORT) {
Dart_Handle send_port = HandleError(Dart_NewSendPort(service_port));
Dart_SetReturnValue(arguments, send_port);
}
Dart_ExitScope();
}
struct FunctionLookup {
const char* name;
Dart_NativeFunction function;
};
FunctionLookup function_list[] = {
{"SampleExtension_ServicePort", sample_extension_ServicePort},
{NULL, NULL}};
Dart_NativeFunction ResolveName(Dart_Handle name, int argc) {
if (!Dart_IsString(name)) return NULL;
Dart_NativeFunction result = NULL;
Dart_EnterScope();
const char* cname;
HandleError(Dart_StringToCString(name, &cname));
for (int i=0; function_list[i].name != NULL; ++i) {
if (strcmp(function_list[i].name, cname) == 0) {
result = function_list[i].function;
break;
}
}
Dart_ExitScope();
return result;
}
Dart_Handle HandleError(Dart_Handle handle) {
if (Dart_IsError(handle)) Dart_PropagateError(handle);
return handle;
}
When I execute 3 times a method calling the service port :
Hello from Dart
Hello from Dart
Before sleep
Hello from Dart
Hello from c !
Before sleep
Hello from c !
Before sleep
Hello from c !
Until every "Hello from c!", its sleep 5 seconds.
There is a way to be also asynchronous in the C side ?
I have seen :
DART_EXPORT Dart_Port Dart_NewNativePort(const char* name,
Dart_NativeMessageHandler handler,
bool handle_concurrently);
Great ! But ...
/* TODO(turnidge): Currently handle_concurrently is ignored. */
Is there a issue about that ? (I want to vote for it to follow solutions)
While the issue is not fixed, what is the best solution ?
Running code in a C fork ?