hardware transactional memory: _xbegin() return 0 - c++

By gcc docs: x86-transactional-memory-intrinsics.html, when transaction failed/abort, _xbegin() should return a abort status . However, I find it return 0 sometimes. And the frequency is very high. What kind of situation that **_xbegin()**will return 0?
After checking manual, I find many situations may cause this result. For example, CPUID, SYSTEMCALL, CFLUSH.etc. However, I don't think my code has triggered any of them.
Here is my code: Simulating a small bank, a random account transfer 1$ to another account.
#include "immintrin.h"
#include <thread>
#include <unistd.h>
#include <iostream>
using namespace std;
#define n_threads 1
#define OPSIZE 1000000000
typedef struct Account{
long balance;
long number;
} __attribute__((aligned(64))) account_t;
typedef struct Bank{
account_t* accounts;
long size;
} bank_t;
bool done = 0;
long *tx, *_abort, *capacity, *debug, *failed, *conflict, *zero;
void* f1(bank_t* bank, int id){
for(int i=0; i<OPSIZE; i++){
int src = rand()%bank->size;
int dst = rand()%bank->size;
while(src == dst){
dst = rand()%bank->size;
}
while(true){
unsigned stat = _xbegin();
if(stat == _XBEGIN_STARTED){
bank->accounts[src].balance++;
bank->accounts[dst].balance--;
_xend();
asm volatile("":::"memory");
tx[id]++;
break;
}else{
_abort[id]++;
if (stat == 0){
zero[id]++;
}
if (stat & _XABORT_CONFLICT){
conflict[id]++;
}
if (stat & _XABORT_CAPACITY){
capacity[id]++;
}
if (stat & _XABORT_DEBUG){
debug[id]++;
}
if ((stat & _XABORT_RETRY) == 0){
failed[id]++;
break;
}
if (stat & _XABORT_NESTED){
printf("[ PANIC ] _XABORT_NESTED\n");
exit(-1);
}
if (stat & _XABORT_EXPLICIT){
printf("[ panic ] _XBEGIN_EXPLICIT\n");
exit(-1);
}
}
}
}
return NULL;
}
void* f2(bank_t* bank){
printf("_heartbeat function\n");
long last_txs=0, last_aborts=0, last_capacities=0, last_debugs=0, last_faileds=0, last_conflicts=0, last_zeros = 0;
long txs=0, aborts=0, capacities=0, debugs=0, faileds=0, conflicts=0, zeros = 0;
while(1){
last_txs = txs;
last_aborts = aborts;
last_capacities = capacities;
last_debugs = debugs;
last_conflicts = conflicts;
last_faileds = faileds;
last_zeros = zeros;
txs=aborts=capacities=debugs=faileds=conflicts=zeros = 0;
for(int i=0; i<n_threads; i++){
txs += tx[i];
aborts += _abort[i];
faileds += failed[i];
capacities += capacity[i];
debugs += debug[i];
conflicts += conflict[i];
zeros += zero[i];
}
printf("txs\t%ld\taborts\t\t%ld\tfaileds\t%ld\tcapacities\t%ld\tdebugs\t%ld\tconflit\t%ld\tzero\t%ld\n",
txs - last_txs, aborts - last_aborts , faileds - last_faileds,
capacities- last_capacities, debugs - last_debugs, conflicts - last_conflicts,
zeros- last_zeros);
sleep(1);
}
}
int main(int argc, char** argv){
int accounts = 10240;
bank_t* bank = new bank_t;
bank->accounts = new account_t[accounts];
bank->size = accounts;
for(int i=0; i<accounts; i++){
bank->accounts[i].number = i;
bank->accounts[i].balance = 0;
}
thread* pid[n_threads];
tx = new long[n_threads];
_abort = new long[n_threads];
capacity = new long[n_threads];
debug = new long[n_threads];
failed = new long[n_threads];
conflict = new long[n_threads];
zero = new long[n_threads];
thread* _heartbeat = new thread(f2, bank);
for(int i=0; i<n_threads; i++){
tx[i] = _abort[i] = capacity[i] = debug[i] = failed[i] = conflict[i] = zero[i] = 0;
pid[i] = new thread(f1, bank, i);
}
// sleep(5);
for(int i=0; i<n_threads;i++){
pid[i]->join();
}
return 0;
}
Supplements:
All accounts is 64bit aligned. I printed bank->accounts[0], bank->accounts1 address. 0xf41080,0xf410c0。
Using -O0 and asm volatile("":::"memory");therefore there is no instruction reordering problems.
Abort rate increases at time. Here is the result
txs 84 aborts 0 faileds 0 capacities 0 debugs 0 conflit 0 zero 0
txs 17070804 aborts 71 faileds 68 capacities 9 debugs 0 conflit 3 zero 59
txs 58838 aborts 9516662 faileds 9516661 capacities 0 debugs 0 conflit 1 zero 9516661
txs 0 aborts 9550428 faileds 9550428 capacities 0 debugs 0 conflit 0 zero 9550428
txs 0 aborts 9549254 faileds 9549254 capacities 0 debugs 0 conflit 0 zero 9549254
Even through n_threads is 1, the result is same.
If I add coarse lock after fallback as follow, the result seems be correct.
int fallback_lock;
bool
rtm_begin(int id)
{
while(true) {
unsigned stat;
stat = _xbegin ();
if(stat == _XBEGIN_STARTED) {
return true;
} else {
_abort[id]++;
if (stat == 0){
zero[id]++;
}
//call some fallback function
if (stat& _XABORT_CONFLICT){
conflict[id]++;
}
//will not succeed on a retry
if ((stat & _XABORT_RETRY) == 0) {
failed[id]++;
//grab a fallback lock
while (!__sync_bool_compare_and_swap(&fallback_lock,0,1)) {
}
return false;
}
}
}
}
....
in_rtm = rtm_begin(id);
y = fallback_lock;
accounts[src].balance--;
accounts[dst].balance++;
if (in_rtm){
_xend();
}else{
while(!__sync_bool_compare_and_swap(&fallback_lock, 1, 0)){
}
}

The hardware documentation on RTM suggests the following:
The value of EAX can be '0' following an RTM abort. For example, a CPUID instruction when used inside an RTM region causes a transactional abort and may not satisfy the requirements for setting any of the EAX bits. This may result in an EAX value of '0'.
(Where, EAX is the hardware register used to communicate status, that GCC will in turn return to you as the return value of )

Related

Two Threads and a class

Suppose I have a class
class Apple
{
bool flag =false;
Apple()
{
}
};
Apple apple=Apple();
Then a thread is created.
CreateThread(...
The instance apple is somehow passed to the thread.
Now int main program later make changes
apple.flag = true;
The problem is the thread is not detecting it.
In thread function,
if(apple.flag==true)
printf("Value changed");
It will not print anything.
I hope the situation is clear. Thanks in advance.
Edit: Minimal working example:
#include <windows.h>
#include <stdio.h>
class Apple
{
public:
bool flag = false;
Apple()
{
}
};
Apple all[1];
DWORD WINAPI myFunc(LPVOID lpParameter)
{
Apple t = *((Apple*)lpParameter);
for (int i = 0; i < 10; i++)
{
printf("flag = %d\n", t.flag);
Sleep(1000);
}
return 55;
}
int main()
{
int n = 0;
printf("flag is %d", all[n].flag);
DWORD myThreadID;
HANDLE myHandle = CreateThread(0, 0, myFunc, &(all[n]), 0, &myThreadID);
for(int i=0;i<10;i++)
{
if (i == 5)
{
all[n].flag = true;
printf("Value of flag set to %d by main\n", all[n].flag);
}
Sleep(1000);
}
return true;
}
Output
flag is 0flag = 0
flag = 0
flag = 0
flag = 0
flag = 0
Value of flag set to 1 by main
flag = 0
flag = 0
flag = 0
flag = 0
flag = 0

C++: segmentation fault in memset () when returning from procedure

Could anyone help me with my C++ program? I'm experiencing a segmentation fault and I can't find the problem. I'm writing a program for my raspberry pi that communicates with an nRF24L01 sensor network and sends data to a dashboard (Dashing) hosted on my RPi using CURL.
I ran my program with a debugger (gdb), and this is the backtrace I got: (see below for the full source code)
Program received signal SIGSEGV, Segmentation fault.
0xb6fbe0dc in memset () from /usr/lib/arm-linux-gnueabihf/libarmmem.so
(gdb) bt
#0 0xb6fbe0dc in memset () from /usr/lib/arm-linux-gnueabihf/libarmmem.so
#1 0x000119d4 in handleSensorMsg () at myNetworkMaster.cpp:174
#2 0x00000000 in ?? ()
I also checked my program with valgrind, using --leak-check=full. The output:
==20790== Invalid read of size 4
==20790== at 0x484F808: bcm2835_peri_read (in /usr/local/lib/librf24.so.1.1.7)
==20790== Address 0xffffffff is not stack'd, malloc'd or (recently) free'd
==20790==
==20790==
==20790== Process terminating with default action of signal 11 (SIGSEGV)
==20790== Access not within mapped region at address 0xFFFFFFFF
==20790== at 0x484F808: bcm2835_peri_read (in /usr/local/lib/librf24.so.1.1.7)
==20790== If you believe this happened as a result of a stack
==20790== overflow in your program's main thread (unlikely but
==20790== possible), you can try to increase the size of the
==20790== main thread stack using the --main-stacksize= flag.
==20790== The main thread stack size used in this run was 8388608.
==20790==
==20790== HEAP SUMMARY:
==20790== in use at exit: 75,908 bytes in 643 blocks
==20790== total heap usage: 1,232 allocs, 589 frees, 84,668 bytes allocated
==20790==
==20790== LEAK SUMMARY:
==20790== definitely lost: 0 bytes in 0 blocks
==20790== indirectly lost: 0 bytes in 0 blocks
==20790== possibly lost: 0 bytes in 0 blocks
==20790== still reachable: 75,908 bytes in 643 blocks
==20790== suppressed: 0 bytes in 0 blocks
==20790== Reachable blocks (those to which a pointer was found) are not shown.
==20790== To see them, rerun with: --leak-check=full --show-reachable=yes
==20790==
==20790== For counts of detected and suppressed errors, rerun with: -v
==20790== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
The source code: the crash occurs in handleSensorMsg(), after the first call to sendDataToDashBoard(). What happens is that the program starts and listens for messages on the nRF24L01. The first one it will receive is a sensor message. It reads the contents and sends the temperature data to the dashboard. After that it will crash. As you can see I'm not used to programming in C(++), my experience is limited to a few simple arduino programs.
/** use Raspberry pi as master node for RF24Network, based on example code from TMRh20
*
* This example sketch shows how to manually configure a node via RF24Network as a master node, which
* will receive all data from sensor nodes.
*
* send received data to Dashing dashboard using curl
*
* listen for messages on the program queue to send data to a node
*
*/
#include <RF24/RF24.h>
#include <RF24Network/RF24Network.h>
#include <curl/curl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
#include <mqueue.h>
#include <time.h>
#include "common.h"
/**
* g++ -L/usr/lib main.cc -I/usr/include -o main -lrrd
**/
//using namespace std;
// CE Pin, CSN Pin, SPI Speed
// Setup for GPIO 22 CE and GPIO 25 CSN with SPI Speed # 1Mhz
//RF24 radio(RPI_V2_GPIO_P1_22, RPI_V2_GPIO_P1_18, BCM2835_SPI_SPEED_1MHZ);
// Setup for GPIO 22 CE and CE0 CSN with SPI Speed # 4Mhz
//RF24 radio(RPI_V2_GPIO_P1_15, BCM2835_SPI_CS0, BCM2835_SPI_SPEED_4MHZ);
// Setup for GPIO 22 CE and CE1 CSN with SPI Speed # 8Mhz
RF24 radio(RPI_V2_GPIO_P1_15, BCM2835_SPI_CS0, BCM2835_SPI_SPEED_8MHZ);
RF24Network network(radio);
CURL *curl;
//CURLcode res;
mqd_t mq;
const char* AUTH_TOKEN = "MODEL_M";
const char* DASHBOARD_IP = "http://192.168.0.21:80/";
const int CURL_BUFFER_SIZE = 100;
class timer {
private:
time_t begTime;
public:
bool isRunning = false;
void start() {
begTime = time(NULL);
isRunning = true;
}
int elapsedTime() {
return (time(NULL) - begTime);
}
bool isTimeout(int seconds) {
int elapsed = elapsedTime();
//printf("%f\n", elapsed);
return elapsed >= seconds;
}
};
const int AVG_TEMP_SAMPLESIZE = 60;
const float TEMP_HIVAL = 999;
const float TEMP_LOVAL = -273.15;
const int DAILY_TEMP_RST_HOUR = 0;
float avgTemperature = TEMP_HIVAL;
float minTemperature = TEMP_HIVAL;
float maxTemperature = TEMP_LOVAL;
float minDailyTemp = TEMP_HIVAL;
float maxDailyTemp = TEMP_LOVAL;
// TODO: create 'message queue'?
const int SEND_RELAY_INTERVAL = 1;
timer relayMsgTimer;
const int SEND_DASH_WAIT = 1;
timer relayDashTimer;
const int SEND_QUERY_INTERVAL = 10;
timer queryMsgTimer;
bool timedRelayMode = true;
int timedRelayState = 1;
const int TIMED_RELAY_ON_HOUR = 6;
const int TIMED_RELAY_OFF_HOUR = 0;
const int TIMED_RELAY_RST_HOUR = 12;
void setCurrentTimestamp(char* timestamp) {
time_t rawTime = time(NULL);
struct tm *tm = localtime(&rawTime);
strftime(timestamp, 20, "%Y-%m-%d %H:%M:%S", tm);
}
void sendDataToDashBoard(const char* const widget, const char* const data) {
char url[CURL_BUFFER_SIZE];
char postFields[CURL_BUFFER_SIZE];
std::fill(url, url + CURL_BUFFER_SIZE, 0);
std::fill(postFields, postFields + CURL_BUFFER_SIZE, 0);
sprintf(url, "%swidgets/%s", DASHBOARD_IP, widget);
curl_easy_setopt(curl, CURLOPT_URL, url);
sprintf(postFields, "{\"auth_token\":\"%s\",%s", AUTH_TOKEN, data);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postFields);
printf("%s%s\n", url, postFields);
CURLcode res = curl_easy_perform(curl);
if (res != CURLE_OK)
printf("curl_easy_perform failed: %s\n", curl_easy_strerror(res));
curl_easy_reset(curl);
} // <-- this is where the debugger stops !!!
void handleSensorMsg() {
RF24NetworkHeader header = 0;
network.read(header,&sensorData,sizeof(sensorData));
char timestamp[20];
std::fill(timestamp, timestamp + 20, 0);
setCurrentTimestamp(timestamp);
printf("%s - %c: Rcv %d %u from 0%o\n", timestamp, SENSOR_MSG, sensorData.temperature, sensorData.humidity, header.from_node);
// ignore probable invalids -- TODO: what if first reading is invalid? => avgTemperature
if (header.from_node != SENSOR_NODE ||
(avgTemperature != TEMP_HIVAL &&
(sensorData.temperature > avgTemperature * 20.0 ||
sensorData.temperature < avgTemperature * 5.0))) {
printf("ignored invalid data\n");
return;
}
float temperature = sensorData.temperature / 10.0;
int humidity = sensorData.humidity / 10.0 + 0.5;
if (avgTemperature == TEMP_HIVAL)
avgTemperature = temperature;
else {
avgTemperature -= avgTemperature / AVG_TEMP_SAMPLESIZE;
avgTemperature += temperature / AVG_TEMP_SAMPLESIZE;
}
if (temperature > maxDailyTemp) {
maxDailyTemp = temperature;
if (temperature > maxTemperature)
maxTemperature = temperature;
} else if (temperature < minDailyTemp) {
minDailyTemp = temperature;
if (temperature < minTemperature)
minTemperature = temperature;
}
char data[CURL_BUFFER_SIZE];
std::fill(data, data + CURL_BUFFER_SIZE, 0);
sprintf(data, "\"current\":%.1f,\"average\":%f,\"moreinfo\":\"Min : %.1f (%.1f) - Max : %.1f (%.1f)\"}",
temperature, avgTemperature, minDailyTemp, minTemperature, maxDailyTemp, maxTemperature);
sendDataToDashBoard("temperature", data); // This is the call that crashes!!!
std::fill(data, data + CURL_BUFFER_SIZE, 0);
sprintf(data, "\"value\":%d}", humidity);
sendDataToDashBoard("humidity", data);
}
void handleRelayMsg() {
RF24NetworkHeader header = 0;
network.read(header, &relayData, sizeof(relayData));
char timestamp[20];
std::fill(timestamp, timestamp + 20, ' ');
setCurrentTimestamp(timestamp);
printf("%s - %c: Rcv %d from 0%o\n", timestamp, RELAY_MSG, relayData.state, header.from_node);
// handle invalid reading
if (header.from_node != RELAY_NODE ||
(relayData.state != true && relayData.state != false)) {
printf("ignored invalid data\n");
queryMsgTimer.start();
return;
}
// delay send of relayData to dashboard to avoid race condition
relayDashTimer.start();
relayMsgTimer.isRunning = false;
queryMsgTimer.isRunning = false;
}
bool sendRelayData() {
RF24NetworkHeader header(/*to node*/ RELAY_NODE, RELAY_MSG);
char timestamp[20];
std::fill(timestamp, timestamp + 20, ' ');
setCurrentTimestamp(timestamp);
printf("%s - %c: Snd %d to %o\n", timestamp, RELAY_MSG, relayData.state, RELAY_NODE);
if (!network.write(header, &relayData, sizeof(relayData))) {
relayMsgTimer.start();
printf("Send failed...\n");
return false;
}
printf("Send OK\n");
return true;
}
void sendQueryMsgToRelay() {
RF24NetworkHeader header(/*to node*/ RELAY_NODE, QUERY_MSG);
char timestamp[20];
std::fill(timestamp, timestamp + 20, ' ');
setCurrentTimestamp(timestamp);
printf("%s - %c: Snd to %o\n", timestamp, QUERY_MSG, RELAY_NODE);
if (!network.write(header, NULL, 0)) {
queryMsgTimer.start();
printf("Send failed...\n");
return;
}
printf("Send OK\n");
queryMsgTimer.isRunning = false;
}
bool readMessageQueue() {
ssize_t bytes_read;
char buffer[MAX_SIZE + 1];
std::fill(buffer, buffer + MAX_SIZE + 1, ' ');
/* receive the message */
bytes_read = mq_receive(mq, buffer, MAX_SIZE, NULL);
if (bytes_read >= 0) {
buffer[bytes_read] = '\0';
char timestamp[20];
std::fill(timestamp, timestamp + 20, ' ');
setCurrentTimestamp(timestamp);
printf("%s - Received: %s\n", timestamp, buffer);
if (!strncmp(buffer, MSG_ON, strlen(MSG_ON))) {
if (relayMsgTimer.isRunning)
return false;
relayData.state = true;
queryMsgTimer.isRunning = false;
sendRelayData();
} else if (!strncmp(buffer, MSG_OFF, strlen(MSG_OFF))) {
if (relayMsgTimer.isRunning)
return false;
relayData.state = false;
queryMsgTimer.isRunning = false;
sendRelayData();
} else if (!strncmp(buffer, MSG_SET, strlen(MSG_SET))) {
if (relayMsgTimer.isRunning)
return false;
relayData.state = !relayData.state;
queryMsgTimer.isRunning = false;
sendRelayData();
} else if (!strncmp(buffer, MSG_GET, strlen(MSG_GET))) {
if (queryMsgTimer.isRunning)
return false;
sendQueryMsgToRelay();
} else if (!strncmp(buffer, MSG_TIMER, strlen(MSG_TIMER))) {
timedRelayMode = !timedRelayMode;
timedRelayState = 1;
printf("timedRelayMode=%d\n", timedRelayMode);
} else if (!strncmp(buffer, MSG_STOP, strlen(MSG_STOP)))
return true;
}
return false;
}
void sendRelayDataToDashboard() {
char data[CURL_BUFFER_SIZE];
std::fill(data, data + CURL_BUFFER_SIZE, 0);
sprintf(data, "\"status\":\"%s\"}", relayData.state ? "ON" : "OFF");
sendDataToDashBoard("relay", data);
relayDashTimer.isRunning = false;
}
int getCurrentHour() {
time_t rawTime = time(NULL);
struct tm *tm = localtime(&rawTime);
return tm->tm_hour;
}
void setTimedRelayState() {
char timestamp[20];
std::fill(timestamp, timestamp + 20, ' ');
setCurrentTimestamp(timestamp);
printf("%s - Timed relay event:\n", timestamp);
relayData.state = !relayData.state;
sendRelayData();
}
void updateTimedRelay(int hour) {
if (timedRelayState == 1 && relayData.state && hour == TIMED_RELAY_OFF_HOUR) {
setTimedRelayState();
timedRelayState = 2;
} else if (timedRelayState == 2 && !relayData.state && hour == TIMED_RELAY_ON_HOUR) {
setTimedRelayState();
timedRelayState = 1;
} else if (timedRelayState == 2 && hour == TIMED_RELAY_RST_HOUR)
timedRelayState = 1;
}
void updateDailyTemperature(int hour) {
if (hour == DAILY_TEMP_RST_HOUR) {
char timestamp[20];
std::fill(timestamp, timestamp + 20, ' ');
setCurrentTimestamp(timestamp);
minDailyTemp = avgTemperature;
maxDailyTemp = avgTemperature;
printf("%s - daily temperatures reset\n", timestamp);
}
}
int main(int argc, char** argv)
{
// Refer to RF24.h or nRF24L01 DS for settings
radio.begin();
delay(5);
network.begin(CHANNEL, MASTER_NODE);
radio.setDataRate(RF24_250KBPS);
radio.setCRCLength(RF24_CRC_8);
// increase delay for network ACK
network.routeTimeout = 300;
radio.printDetails();
// CURL setup for sending data to dashboard
curl_global_init(CURL_GLOBAL_ALL);
curl = curl_easy_init();
if (curl == NULL) {
printf("Error getting curl handle.\n");
exit(EXIT_FAILURE);
}
// setup the message queue
struct mq_attr attr;
/* initialize the queue attributes */
attr.mq_flags = 0;
attr.mq_maxmsg = 10;
attr.mq_msgsize = MAX_SIZE;
attr.mq_curmsgs = 0;
/* create the message queue */
mq = mq_open(QUEUE_NAME, O_CREAT | O_RDONLY | O_NONBLOCK, 0644, &attr);
if (mq == -1) {
printf("Failed to create queue.\n");
exit(EXIT_FAILURE);
}
queryMsgTimer.start();
int currentHour = getCurrentHour();
bool exitReceived = false;
while(!exitReceived)
{
network.update();
while ( network.available() ) { // Is there anything ready for us?
RF24NetworkHeader header; // If so, grab it and print it out
network.peek(header);
switch(header.type) {
case SENSOR_MSG: handleSensorMsg();
break;
case RELAY_MSG: handleRelayMsg();
break;
default: network.read(header,0,0);
char timestamp[20];
setCurrentTimestamp(timestamp);
printf("%s - Rcv bad type %d from 0%o\n", timestamp, header.type, header.from_node);
printf("%s\n", header.toString());
break;
}
}
// check for incoming messages on the program queue
exitReceived = readMessageQueue();
// are there any messages that need to be sent?
if (relayMsgTimer.isRunning && relayMsgTimer.isTimeout(SEND_RELAY_INTERVAL))
relayMsgTimer.isRunning = !sendRelayData();
if (relayDashTimer.isRunning && relayDashTimer.isTimeout(SEND_DASH_WAIT))
sendRelayDataToDashboard();
if (queryMsgTimer.isRunning && queryMsgTimer.isTimeout(SEND_QUERY_INTERVAL))
sendQueryMsgToRelay();
// timed events
if (currentHour != getCurrentHour()) {
currentHour = getCurrentHour();
// check if relay needs to be switched on or off based on timer
if (timedRelayMode)
updateTimedRelay(currentHour);
// reset daily temperature min&max
updateDailyTemperature(currentHour);
}
delay(100);
fflush(stdout);
}
/* cleanup */
curl_easy_cleanup(curl);
curl_global_cleanup();
mq_close(mq);
mq_unlink(QUEUE_NAME);
return 0;
}
The common.h include:
#ifndef COMMON_H_
#define COMMON_H_
#define CHANNEL 1
#define QUEUE_NAME "/rf24_queue"
#define MAX_SIZE 1024
#define MSG_STOP "exit"
#define MSG_ON "ON"
#define MSG_OFF "OFF"
#define MSG_SET "SET"
#define MSG_GET "GET"
#define MSG_TIMER "TIMER"
#define MASTER_NODE 0
#define SENSOR_NODE 01
#define RELAY_NODE 01
#define SENSOR_MSG '1'
#define RELAY_MSG 'R'
#define QUERY_MSG 'Q'
#ifndef AM2320_H
struct sensorData_t {
int16_t temperature;
uint16_t humidity;
} sensorData;
#endif
struct relayData_t {
bool state;
} relayData;
typedef enum { wdt_16ms = 0, wdt_32ms, wdt_64ms, wdt_128ms, wdt_250ms, wdt_500ms, wdt_1s, wdt_2s, wdt_4s, wdt_8s } wdt_prescalar_e;
#endif /* #ifndef COMMON_H_ */
The RF24 libraries are available from here: https://github.com/TMRh20/RF24. Thanks for your time!
The offending code was this block here (in sendDataToDashBoard):
CURLcode res = curl_easy_perform(curl);
if (res != CURLE_OK)
printf("curl_easy_perform failed: %s\n", curl_easy_strerror(res));
curl_easy_reset(curl);
I commented out the curl_easy_reset() call and now it doesn't crash anymore. I don't know why, but there you have it. I think I don't need to do a reset since I always set the same options on every perform (URL & POSTFIELDS), so this works for me.

Sometimes getting null value for windows version and processor type

For the most part, the function below works but in rare cases returns a null value:
DWORD WinVerMinor() {
OSVERSIONINFO osvi;
ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&osvi);
return osvi.dwMinorVersion;
}
Also cpustr below sometimes ends up being null. For example, from an executable app cpustr stores the correct string while the very same code produces a null result in a dll (sometimes).
char cpustr[255]
void proctype()
{
int nBuff[4];
char szMan[13];
char szFeatures[256];
unsigned nProcessorType;
// Get CPU manufacturer and highest CPUID
__cpuid(nBuff, 0);
nHighestFeature = (unsigned)nBuff[0];
*(int*)&szMan[0] = nBuff[1];
*(int*)&szMan[4] = nBuff[3];
*(int*)&szMan[8] = nBuff[2];
szMan[12] = 0;
if(strcmp(szMan, "AuthenticAMD") == 0)
nProcessorType = 0;
else if(strcmp(szMan, "GenuineIntel") == 0)
nProcessorType = 1;
else
nProcessorType = 2;
__cpuid(nBuff, 0x80000000);
nHighestFeatureEx = (unsigned)nBuff[0];
if(nHighestFeatureEx >= 0x80000004)
{
char szCPUName[49];
szCPUName[0] = 0;
__cpuid((int*)&szCPUName[0], 0x80000002);
__cpuid((int*)&szCPUName[16], 0x80000003);
__cpuid((int*)&szCPUName[32], 0x80000004);
szCPUName[48] = 0;
for(int i=(int)strlen(szCPUName)-1; i>=0; --i)
{
if(szCPUName[i] == ' ')
szCPUName[i] = '\0';
else
break;
}
for (int z=0; z < strlen(szCPUName); z++) {
cpustr[z] = szCPUName[z]; }
}
return 0;
}
What is the reason for the (sometimes) null values?

how to fill the "data field" of wavfile

Hi i am trying to record from a board and i have successfully record 4 seconds. Problem is when i try to record for more time, i got an error telling me that there not enough memory. my target is to record a 5 minutes file. Until now i have create a buffer named snIn[256] where are the samples. i send it to a big buffer of [16K * 4sec] and when it is full, i create the wav file.
#include "SAI_InOut.hpp"
#include "F746_GUI.hpp"
#include "Delay.hpp"
#include "WaveformDisplay.hpp"
#include "SDFileSystem.h"
#include "wavfile.h"
using namespace Mikami;
#define RES_STR_SIZE 0x20
#define WAVFILE_SAMPLES_PER_SECOND 16000
#define REC_TIME 4
//Create an SDFileSystem object
SDFileSystem sd("sd");
bool flag = 1;
int count = 0;
char *res_buf;
int rp = 0;
const int NUM_SAMPLES = WAVFILE_SAMPLES_PER_SECOND * REC_TIME;
Array<int16_t> my_buffer(NUM_SAMPLES);
int j = 0;
static const char *target_filename = "/sd/rectest.wav";
const int SEG_SIZE = 256;
int sent_array = 0;
int rec(const char *filename, Array<int16_t> my_buffer)
{
j = 0;
flag = 0;
sent_array = 0;
WavFileResult result;
wavfile_info_t info;
wavfile_data_t data;
WAVFILE_INFO_AUDIO_FORMAT(&info) = 1;
WAVFILE_INFO_NUM_CHANNELS(&info) = 1;
WAVFILE_INFO_SAMPLE_RATE(&info) = WAVFILE_SAMPLES_PER_SECOND;
WAVFILE_INFO_BITS_PER_SAMPLE(&info) = 16;
WAVFILE_INFO_BYTE_RATE(&info) = WAVFILE_INFO_NUM_CHANNELS(&info) * WAVFILE_INFO_SAMPLE_RATE(&info) * (WAVFILE_INFO_BITS_PER_SAMPLE(&info) / 8);
WAVFILE_INFO_BLOCK_ALIGN(&info) = 2;
WAVFILE *wf = wavfile_open(filename, WavFileModeWrite, &result);
if (result != WavFileResultOK) {
wavfile_result_string(result, res_buf, RES_STR_SIZE);
printf("%s", res_buf);
return result;
} else printf ("Open file success \r\n");
rp = 0;
WAVFILE_DATA_NUM_CHANNELS(&data) = 1;
result = wavfile_write_info(wf, &info);
if (result != WavFileResultOK) {
wavfile_result_string(result, res_buf, RES_STR_SIZE);
printf("%s", res_buf);
return result; } else printf ("Write info success \r\n");
while ( rp < NUM_SAMPLES ) {
WAVFILE_DATA_CHANNEL_DATA(&data, 0) = my_buffer[rp];
result = wavfile_write_data(wf, &data);
rp += 1;
}
if (result != WavFileResultOK) {
wavfile_result_string(result, res_buf, RES_STR_SIZE);
printf("%s", res_buf);
return result; } else printf ("Write Data file success \r\n");
result = wavfile_close(wf);
if (result != WavFileResultOK) {
wavfile_result_string(result, res_buf , RES_STR_SIZE);
printf("%s", res_buf);
return result; } else printf ("Close file success \r\n");
//UnMount the filesystem
sd.unmount();
printf("Success rec !\r\n");
return 0;
}
int main()
{
//Mount the filesystem
sd.mount();
const float MAX_DELAY = 0.5f; // 最大遅延,単位:秒
const int FS = I2S_AUDIOFREQ_16K; // 標本化周波数: 16 kHz
const uint32_t MAX_ARRAY_SIZE = (uint32_t)(MAX_DELAY*FS);
SaiIO mySai(SaiIO::BOTH, 256, FS, INPUT_DEVICE_DIGITAL_MICROPHONE_2);
Label myLabel(185, 10, "Delay System", Label::CENTER, Font16);
// ButtonGroup: "ON", "OFF"
const uint16_t BG_LEFT = 370;
const uint16_t BG_WIDTH = 100;
const uint16_t BG_HEIGHT = 45;
ButtonGroup onOff(BG_LEFT, 40, BG_WIDTH/2, BG_HEIGHT,
2, (string[]){"ON", "OFF"}, 0, 0, 2, 1);
const uint16_t SB_LEFT = BG_LEFT - 320;
const uint16_t SB_WIDTH = 270;
const uint16_t SB_Y0 = 240;
char str[20];
sprintf(str, " %3.1f [s]", MAX_DELAY);
SeekBar barDelay(SB_LEFT, SB_Y0, SB_WIDTH,
0, MAX_ARRAY_SIZE, 0, "0", "", str);
NumericLabel<float> labelDelay(SB_LEFT+SB_WIDTH/2, SB_Y0-40, "DELEY: %4.2f", 0, Label::CENTER);
DelaySystem delaySystem(MAX_ARRAY_SIZE);
WaveformDisplay displayIn(*GuiBase::GetLcdPtr(), SB_LEFT+7, 70, 256, 9,LCD_COLOR_WHITE, LCD_COLOR_CYAN,GuiBase::ENUM_BACK);
Label inLabel(SB_LEFT-30, 65, "IN");
WaveformDisplay displayOut(*GuiBase::GetLcdPtr(), SB_LEFT+7, 130, 256, 9,LCD_COLOR_WHITE, LCD_COLOR_CYAN,GuiBase::ENUM_BACK);
Label outLabel(SB_LEFT-30, 125, "OUT");
int runStop = 1;
Array<int16_t> snIn(mySai.GetLength());
Array<int16_t> snOut(mySai.GetLength());
mySai.RecordIn();
mySai.PlayOut();
mySai.PauseOut();
while (true)
{
// On/OFF
int num;
if (onOff.GetTouchedNumber(num))
if (runStop != num)
{
if (num == 0) mySai.ResumeOut();
else mySai.PauseOut();
runStop = num;
}
if (mySai.IsCompleted())
{
for (int n=0; n<mySai.GetLength() ; n++)
{
int16_t xL, xR;
mySai.Input(xL,xR);
int16_t xn = xL + xR;
snIn[n] = xn;
my_buffer[j] = xn;
j++;
if (j == NUM_SAMPLES && flag == 1) {
rec (target_filename , my_buffer); }
int16_t yn = delaySystem.Execute(xn);
mySai.Output(yn, yn);
snOut[n] = yn;
}
mySai.Reset();
displayIn.Execute(snIn);
}
}
}
I thought about a possible solution, to fill directly the "data field" of the wavefile with the snIn[256] buffer (instead of using my_buffer) again and again and at the end close the wavfile. Please let me know what you think about that and other solutions
things to note: 1) while a write operation is being performed, more data is still coming in.
At the very least I would double buffer that data, so can be writing one buffer while the other one fills.
Usually this means using an interrupt to collect the samples (into which ever buffer is currently being filed.)
the foreground program waits for the current buffer to be 'full', then initiates write operation.,
then waits again for a buffer to be 'full'
The interrupt function tracks which buffer is being filled and the current index into that buffer. When a buffer is full, set a 'global' status to let the foreground program know which buffer is ready to be written.
The foreground program writes the buffer, then resets the status for that buffer.

How to make three processes work in C/C++

I have to make three processes A, B and C that use shared memory. A and B write 100 integers in the shared memory, and C reads them and writes them to a binary file. That is what I made, but it doesn't work properly. I include <stdio.h>, <math.h>, <fcntl.h> and <time.h>. How to make it work?
struct sync
{
int n;
int lock;
int generated;
char process;
} *b;
int testandset(int* lockPtr)
{
int oldValue = *lockPtr;
return 0 != oldValue;
}
int main()
{
struct sync buff;
int pid, ppid, fp, i;
srand(time(NULL));
b = (struct sync*)malloc(666);
b->n = 0;
b->lock = 0;
b->generated = 0;
i = 0;
printf("Generating numbers\n");
pid = fork();
if (0 == pid)
{
while (100 >= b->generated)
{
while (testandset(&(b->lock)))
{
}
buff.n = rand() % 1001;
buff.process = 'A';
fp = open("db", O_RDWR | O_APPEND);
if (-1 == fp)
fp = open("db", O_CREAT);
write(fp, &buff, sizeof(struct sync));
close(fp);
b->generated++;
b->lock = 0;
}
}
if (0 < pid)
{
ppid = fork();
if (0 == ppid)
{
while (100 >= b->generated)
{
while (testandset(&(b->lock)))
{
}
buff.n = rand() % 1001;
buff.process = 'B';
printf("No: %d %d \n", ++i, buff.n);
fp = open( "db", O_RDWR | O_APPEND );
if (-1 == fp)
fp = open("db", O_CREAT);
write(fp, &buff, sizeof(struct sync));
close(fp);
b->generated++;
b->lock = 0;
}
}
if (0 < ppid)
{
wait();
i = 0;
fp = open("db", O_RDONLY, 0755);
printf("Reading from file\n");
while (read(fp, &buff, sizeof(struct sync)))
{
if ('A' == buff.process)
i++;
}
close(fp);
int vals[i];
i = 0;
fp = open("db", O_RDONLY, 0666);
while (read(fp, &buff, sizeof(struct sync)))
{
if ('A' == buff.process)
vals[i++] = buff.n;
}
close(fp);
fp = open("db", O_RDONLY, 0455);
int i;
for(i = 0; i < i; i++)
write((const void*) &vals[i],sizeof(int),1,fp);
}
wait();
}
return 0;
}
Files are not really reliable for mutliprocess sharing information (and editing at the same time), You'd rather use a real database in transaction mode or use IPC http://www.cs.cf.ac.uk/Dave/C/node27.html. Or maybe re-design and use threads and mutex.
There are many issues here, but I will concentrate on testandset(). Firstly, it's misnamed, it doesn't set anything, nor do you set b->lock anywhere. What's it for?
It seems to me that you might be trying to use it for some sort of locking between processes, but it won't work. When you fork, the new child effectively gets a complete copy of the parent's address space and changes to variables in the parent will not be seen in the child, and vice versa. As Maresh says, you need to look at using inter process communication.