proper way to create multiple forked threads - c

I'm creating a timer function for a bit of embedded code that will allow me to bypass certain GPIO checks while a certain process is running, i.e., when the timer is running in a non-blocking manner.
This seems to run just fine the first 11 times the operations occur, but every time, on the 11th iteration the system will crash. The likely culprit is something in how the timer thread is being handled. My guess is there's some bit of memory cleanup that I'm not handling properly and that's leading to memory leaks of some kind. But I'm really not sure.
I can see through debug tracing that the thread is exiting after each iteration.
Here is the timer code:
#include <time.h>
#include <semaphore.h>
#include <pthread.h>
#include <msp432e4_timer.h>
extern void TaskSleep(uint32_t delay);
static bool timerActive;
static sem_t timerSem;
pthread_t timerThread;
pthread_attr_t attrs;
struct sched_param priParam;
static void *msp432e4_timer(void *argUnused) {
sem_wait(&timerSem);
timerActive = true;
sem_post(&timerSem);
TaskSleep(40);
sem_wait(&timerSem);
timerActive = false;
sem_post(&timerSem);
return (NULL);
}
void initTimer() {
int retc;
pthread_attr_init(&attrs);
priParam.sched_priority = 1;
retc = pthread_attr_setschedparam(&attrs, &priParam);
retc |= pthread_attr_setdetachstate(&attrs, PTHREAD_CREATE_DETACHED);
retc |= pthread_attr_setstacksize(&attrs, 1024);
if (retc != 0) {
// failed to set attributes
while (1) {}
}
timerActive = false;
if((sem_init(&timerSem, 0, 0)) != 0) {
while(1);
}
sem_post(&timerSem);
}
/*
* return true on starting a new timer
* false implies timer already active
*/
void timerStart() {
int retc;
retc = pthread_create(&timerThread, &attrs, msp432e4_timer, NULL);
if (retc != 0) {
// pthread_create() failed
while (1) {}
}
}
/* return true if timer active */
bool timerCheck() {
bool retval;
sem_wait(&timerSem);
retval = timerActive;
sem_post(&timerSem);
return(retval);
}
The TaskSleep function is a call to a freeRTOS TaskDelay function. It's used in many points throughout the system and has never been an issue.
Hopefully someone can point me in the right direction.

But you didn't really post enough of your code to determine where the problems might be, but I thought this might be worth mentioning:
A general problem is that the sample code you have is open loop wrt thread creation; that is there is nothing to throttle it, and if your implementation has a particularly slow thread exit handling, you could have many zombie threads lying around that haven't died yet.
In typical embedded / real time systems, you want to move resource allocation out of the main loop, since it is often non deterministic. So, more often you would create a timer thread, and park it until it is needed:
void *TimerThread(void *arg) {
while (sem_wait(&request) == 0) {
msp432e4_timer(void *arg);
}
return 0
}
void TimerStart(void) {
sem_post(&request);
}

Related

How can I fake mutex context in C/C++?

I've been reading through and attempting to apply Tyler Hoffman's C/C++ unit testing strategies.
He offers the following as a way to fake a mutex:
#define NUM_MUTEXES 256
typedef struct Mutex {
uint8_t lock_count;
} Mutex;
static Mutex s_mutexes[NUM_MUTEXES];
static uint32_t s_mutex_index;
// Fake Helpers
void fake_mutex_init(void) {
memset(s_mutexes, 0, sizeof(s_mutexes));
}
bool fake_mutex_all_unlocked(void) {
for (int i = 0; i < NUM_MUTEXES; i++) {
if (s_mutexes[i].lock_count > 0) {
return false;
}
}
return true;
}
// Implementation
Mutex *mutex_create(void) {
assert(s_mutex_index < NUM_MUTEXES);
return &s_mutexes[s_mutex_index++];
}
void mutex_lock(Mutex *mutex) {
mutex->lock_count++;
}
void mutex_unlock(Mutex *mutex) {
mutex->lock_count--;
}
For a module that has functions like:
#include "mutex/mutex.h"
static Mutex *s_mutex;
void kv_store_init(lfs_t *lfs) {
...
s_mutex = mutex_create();
}
bool kv_store_write(const char *key, const void *val, uint32_t len) {
mutex_lock(s_mutex); // New
...
mutex_unlock(s_mutex); // New
analytics_inc(kSettingsFileWrite);
return (rv == len);
}
After being setup in a test like:
TEST_GROUP(TestKvStore) {
void setup() {
fake_mutex_init();
...
}
...
}
I'm confused about a couple things:
How does fake_mutex_init() cause methods using mutex_lock and mutex_unlock to use the fake lock and unlock?
How does this actually fake mutex locking? Can I produce deadlocks with these fakes? Or, should I just be checking the lock count in my tests?
How does fake_mutex_init() cause methods using mutex_lock and mutex_unlock to use the fake lock and unlock?
It doesn't. It's unrelated.
In the tutorial, the tests are linked with one of the implementations. In the case of this specific test, it is linked with this fake mutex implementation.
How does this actually fake mutex locking?
It just increments some integers inside an array. There is no "locking" involved in any way.
Can I produce deadlocks with these fakes?
No, because there is locking, there is no waiting, so there are no deadlocks, which occur when two threads wait for each other.
Or, should I just be checking the lock count in my tests?
Not, in "tests" - for tests mutex is an abstract thing.
Adding assert(mutex->lock_count > 0) to unlock to check if your tests do not unlock a mutex twice seems like an obvious improvement.

Binary Semaphore to synchronize an Interrupt with a task in FreeRTOS

Hello everyone im doing my first steps with RTOS. Im trying to receive an amount of data using UART in an interrupt mode. I have a Display Task where the commands are being written to a global buffer, and i just created a UART Handler Task where i want to read the bytes. The problems im facing are.
The semaphore i use inside the UART Task is unknown, even though i declared it global in the main function, so the xSemaphoreTake() function has errors there. Maybe a helpful Note: the UART Task is in a seperated file.
Is my implemntation of the HAL_UART_RxCpltCallback and the UART Task clean?
here is the code i wrote:
SemaphoreHandle_t uartInterruptSemaphore = NULL;
int main(void)
{
/* USER CODE BEGIN 1 */
void mainTask(void* param) {
uartInterruptSemaphore = xSemaphoreCreateBinary();
if(uartInterruptSemaphore != NULL) {
// Display Thread with a 2 priority
xTaskCreate(&displayTask, "Display Thread", 1000, &huart4, 2, NULL);
// deferred Interrupt to be synchronized with the Display Task, must have a higher priority than the display task
xTaskCreate(&UartHandlerTask, "UART Handler Task", 1000, &huart4, 3, NULL);
}
for(;;){
}
}
the callback function i wrote:
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *uart_cb) {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
if(uart_cb->Instance == USART4) {
xSemaphoreGiveFromISR(uartInterruptSemaphore, &xHigherPriorityTaskWoken);
}
portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
}
and the handler task:
void UartHandlerTask(void* param) {
huart_cache = param;
const uint8_t tmp = rx_byte; //rx byte is global volatile variable
for(;;){
if(xSemaphoreTake(uartInterruptSemaphore, portMAX_DELAY) == pdPASS) {
HAL_UART_Receive_IT((UART_HandleTypeDef *)huart_cache, (uint8_t *)&rx_byte, 1);
// write data to the buffer
RX_interrupt(tmp);
}
}
}
I would recommend getting a better handle on C before trying to use an RTOS. This will also show you a better way of unblocking a task form an interrupt than using a binary semaphore: https://www.freertos.org/2020/09/decrease-ram-footprint-and-accelerate-execution-with-freertos-notifications.html

switching up/down the stack with getcontext/setcontext

I am trying to understand if getcontext/setcontext will work correctly in a specific scenario.
I can see how setcontext() can be used to unwind the stack back to a certain place in history.
#include <stdio.h>
#include <ucontext.h>
int rollback = 0;
ucontext_t context;
void func(void)
{
setcontext(cp);
}
int main(void)
{
getcontext(&context);
if (rollback == 0)
{
printf("getcontext has been called\n");
rollback++;
func();
}
else
{
printf("setcontext has been called\n");
}
}
But I was wondering if after an unwind you can re-wind back to a place that was in the future? I suppose this depends on the getcontext() call captures a copy of the stack and I can't find the exact details in the documentation.
#include <stdio.h>
#include <ucontext.h>
int rollback = 0;
int backToFuture = 0;
ucontext_t context;
ucontext_t futureContext;
void func(void)
{
// Some complex calc
if (some-condition)
{
getcontext(&futureContext); // After returning I want to come back
// here to carry on with my work.
if (backToFuture == 0)
{
setcontext(&context); // rewind to get stuff-done
}
}
// Finishe work
}
int main(void)
{
getcontext(&context);
if (rollback == 0)
{
printf("getcontext has been called\n");
rollback++;
func();
// eventually always return here.
}
else
{
printf("setcontext has been called\n");
// Do specialized work that needed to be done
// May involve function calls.
//
// I worry that anything the adds new stack frames
// will disrupt the saved state of futureContext
//
// But without detailed information I can not be sure
// if this is an allowed senario.
backToFuture = 1;
setcontext(&futureContext);
}
}
getcontext doesn't copy stack, it only dumps registers (including stack pointer) and a little context data like signal mask, etc.
When you jump down the stack it invalidates the top context. Even if you won't do any function calls think about the signal handler that can execute there. If you want to jump between two stacks you need to makecontext.
I added variable that demonstrates that your code is invalid:
void func(void)
{
// Some complex calc
if (1)
{
volatile int neverChange = 1;
getcontext(&futureContext); // After returning I want to come back
// here to carry on with my work.
printf("neverchange = %d\n", neverChange);
if (backToFuture == 0)
{
setcontext(&context); // rewind to get stuff-done
}
}
// Finishe work
}
On my machine it results in:
getcontext has been called
neverchange = 1
setcontext has been called
neverchange = 32767

C static variable not updating

I'm having a problem with my C code where I declare a static int variable (as a flag), then initialize it to -1 in init() which is only called once, then when I try to update the value to 0 or 1 later on, it keeps reverting back to -1.
Does anyone know what the problem can be?
I don't have any local variables with the same identifier so I'm really lost.
Thanks!
static int previousState;
void init()
{
previousState = -1;
}
void moveForward(int currentState)
{
if (previousState == -1)
previousState = currentState;
if (previousState != currentState)
{
/* do stuff */
/* PROBLEM: it never goes into here, because previousState is always -1! */
}
/* other code */
}
void main()
{
init();
if (fork() == 0)
{
/* do stuff */
moveForward(1);
exit();
}
/* more forks */
moveForward(0);
exit();
}
Each process calls moveForward just once. Processes do not share static data!
Use threads, or use shared memory. Also use mutex or semaphore for concurrent access of shared data . Preferably switch to a language better suited for parallel prosessing...

Suspend/Resume all user processes - Is that possible?

I have PC's with a lot of applications running at once, i was thinking is it possible to SUSPEND all applications, i want to do that to run periodically one other application that is using a lot the CPU so want it to have all the processor time.
The thing is i want to suspend all applications run my thing that uses the CPU a lot, then when my thingy exit, to resume all applications and all work to be resumed fine....
Any comments are welcome.
It's possible but not recommended at all.
Set the process and thread priority so your application will be given a larger slice of the CPU.
This also means it won't kill the desktop, any network connections, antivirus, start menu, the window manager, etc as your method will.
You could possibly keep a list that you yourself manually generate of programs that are too demanding (say, for (bad) example, Steam.exe, chrome.exe, 90GB-video-game.exe, etc). Basically, you get the entire list of all running processes, search that list for all of the blacklisted names, and NtSuspendProcess/NtResumeProcess (should you need to allow it to run again in the future).
I don't believe suspending all user processes is a good idea. Much of those are weirdly protected and probably should remain running, anyway, and it's an uphill battle with very little to gain.
As mentioned in another answer, you can of course just adjust your processes priority up if you have permission to do so. This sorts the OS-wide process list in favor of your process, so you get CPU time first.
Here's an example of something similar to your original request. I'm writing a program in C++ that needed this exact feature, so I figured I'd help out. This will find Steam.exe or chrome.exe, and suspend the first one it finds for 10 seconds.. then will resume it. This will show as "not responding" on Windows if you try to interact with the window whilst it's suspended. Some applications may not like being suspended, YMMV.
/*Find, suspend, resume Win32 C++
*Written by jimmio92. No rights reserved. Public domain.
*NO WARRANTY! NO LIABILITY! (obviously)
*/
#include <windows.h>
#include <psapi.h>
typedef LONG (NTAPI *NtSuspendProcess)(IN HANDLE ProcessHandle);
typedef LONG (NTAPI *NtResumeProcess)(IN HANDLE ProcessHandle);
NtSuspendProcess dSuspendProcess = nullptr;
NtResumeProcess dResumeProcess = nullptr;
int get_the_pid() {
DWORD procs[4096], bytes;
int out = -1;
if(!EnumProcesses(procs, sizeof(procs), &bytes)) {
return -1;
}
for(size_t i = 0; i < bytes/sizeof(DWORD); ++i) {
TCHAR name[MAX_PATH] = "";
HMODULE mod;
HANDLE p = nullptr;
bool found = false;
p = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, procs[i]);
if(p == nullptr)
continue;
DWORD unused_bytes_for_all_modules = 0;
if(EnumProcessModules(p, &mod, sizeof(mod), &unused_bytes_for_all_modules)) {
GetModuleBaseName(p, mod, name, sizeof(name));
//change this to use an array of names or whatever fits your need better
if(strcmp(name, "Steam.exe") == 0 || strcmp(name, "chrome.exe") == 0) {
out = procs[i];
found = true;
}
}
CloseHandle(p);
if(found) break;
}
return out;
}
void suspend_process_by_id(int pid) {
HANDLE h = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
if(h == nullptr)
return;
dSuspendProcess(h);
CloseHandle(h);
}
void resume_process_by_id(int pid) {
HANDLE h = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
if(h == nullptr)
return;
dResumeProcess(h);
CloseHandle(h);
}
void init() {
//load NtSuspendProcess from ntdll.dll
HMODULE ntmod = GetModuleHandle("ntdll");
dSuspendProcess = (NtSuspendProcess)GetProcAddress(ntmod, "NtSuspendProcess");
dResumeProcess = (NtResumeProcess)GetProcAddress(ntmod, "NtResumeProcess");
}
int main() {
init();
int pid = get_the_pid();
if(pid < 0) {
printf("Steam.exe and chrome.exe not found");
}
suspend_process_by_id(pid);
//wait ten seconds for demonstration purposes
Sleep(10000);
resume_process_by_id(pid);
return 0;
}

Resources