Timer 0 interruption on PIC18F - c

I am trying to make a program, that use a interruption for timer 0. The problem is I have to add a function with 2 variables.
Timer configuration will be performed by defining a function with the following prototype: void int_tmr0 (int conf_int, int conf_T0), which I did it in that form:
void conf(int p1, int p2)
{
T0CON=p1;
INTCON=p2;
}
I try to put the records: T0CON, INTCON in these 2 variables: p1 and p2.
I am not sure if I can call these 2 variables in the main function by:
void main()
{
WDTCONbits.ADSHR = 1;
MEMCONbits.EBDIS = 1;
TRISD = 0x0;
INTCONbits.GIE = 1;
p1=0b10001000;
INTCONbits.TMR0IE = 0;
}
Here is the whole code:
#include <xc.h>
unsigned char counter;
void interrupt f1()
{
if(INTCONbits.TMR0IE && INTCONbits.TMR0IF)
{
counter++;
INTCONbits.TMROIF=0
}
void conf(int p1, int p2)
{
T0CON=p1;
INTCON=p2;
}
void main()
{
WDTCONbits.ADSHR = 1;
MEMCONbits.EBDIS = 1;
TRISD = 0x0;
INTCONbits.GIE = 1;
p1=0b10001000;
INTCONbits.TMR0IE = 0;
}
while(1){
LATD= counter;
}
}

If I understood it right,
You need to have a function called by the Timer0 interrupt
Your SDK defines this function as void int_tmr0(int conf_int, int conf_T0)
You need your function to receive some other arbitrary parameters
A solution would be to create the function as the SDK requires and store the parameters in global variables. Then, you can call your function from inside the 'callback' function using these variables as parameters:
int volatile param_1 = 0, param_2 = 0;
void int_tmr0(int conf_int, int conf_T0)
{
conf(param_1, param_2);
}
void conf(int p1, int p2)
{
T0CON=p1;
INTCON=p2;
}
int main()
{
WDTCONbits.ADSHR = 1;
MEMCONbits.EBDIS = 1;
TRISD = 0x0;
INTCONbits.GIE = 1;
param_1=0b10001000;
INTCONbits.TMR0IE = 0;
while(1){
LATD= counter;
}
}

Related

Esp32-(xQueueGenericReceive)- assert failed

I have been working on a project in which the analog values are sampled at a particular frequency and stored in an array. Then the value will be sent to user application ESP32 using BLE. But I got stuck in this error.
/home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/freertos/queue.c:1443
(xQueueGenericReceive)- assert failed! abort() was called at PC
0x4008e1d5 on core 1
Backtrace: 0x40091b38:0x3ffe0b20 0x40091d69:0x3ffe0b40
0x4008e1d5:0x3ffe0b60 0x400d1a2d:0x3ffe0ba0 0x4008e525:0x3ffe0be0
Rebooting... ets Jun 8 2016 00:22:57
rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) configsip: 0,
SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1 load:0x3fff0018,len:4 load:0x3fff001c,len:1044
load:0x40078000,len:8896 load:0x40080400,len:5816 entry 0x400806ac
I am Using Esp32arduino and FreeRTOS for programming. The error is in the semaphore from the interrupt but I couldn't be able to find out exact solution. Please help me out guys.
#include <ArduinoJson.h>
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
#if CONFIG_FREERTOS_UNICORE
static const BaseType_t app_cpu = 0;
#else
static const BaseType_t app_cpu = 1;
#endif
//ADC Related Global Variables
static const uint16_t timer_divider = 80;
static const uint64_t timer_max_count = 1000;
static const int adc_pin = A0;
static const int BUF_SIZE = 1000;
static int buf[BUF_SIZE];
int Buff_Len = 0;
static int Read = 0;
static int Write = 0;
static int count = 0;
static float avg = 0;
int i = 0;
int BLE_flag = 0;
String cmd;
static hw_timer_t *timer = NULL;
static uint16_t val;
static int count1 = 0;
static SemaphoreHandle_t bin_sem = NULL;
static SemaphoreHandle_t bin_sem2 = NULL;
static portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED;
//ADC Related Global Variables
//BLE Global Variable
char Reading[4];
BLEServer *pServer = NULL;
BLECharacteristic *pTxCharacteristic;
bool deviceConnected = false;
bool oldDeviceConnected = false;
//Declaration BLE necessary Classes
#define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E" // UART service UUID
#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"
class MyServerCallbacks:public BLEServerCallbacks
{
void onConnect (BLEServer * pServer)
{
deviceConnected = true;
};
void onDisconnect (BLEServer * pServer)
{
deviceConnected = false;
}
};
//BLE Global Variables
//Task Section
void IRAM_ATTR onTimer ()
{
//sampling
xSemaphoreGiveFromISR (bin_sem2, &task_woken);
if (task_woken)
{
portYIELD_FROM_ISR ();
}
}
void move_to_Queue (void *parameters)
{
while (1)
{
xSemaphoreTake (bin_sem2, portMAX_DELAY);
if (Buff_Len == BUF_SIZE || count1 > 2000)
{
Serial.println ("Buffer is full");
xSemaphoreGive (bin_sem);
}
else
{
// storing the instantaneous sample value to buffer
}
}
}
void BLE_Task (void *parameters)
{
while (1) {
xSemaphoreTake (bin_sem, portMAX_DELAY);
Serial.println ("BLE");
// sending the data\lu
delay (10); // bluetooth stack will go into congestion, if too many packets are sent
}
}
Serial.println ();
}
}
void setup ()
{
// put your setup code here, to run once:
Serial.begin (115200);
vTaskDelay (1000 / portTICK_PERIOD_MS);
//BLE Declarations
BLEDevice::init ("UART Service");
pServer = BLEDevice::createServer ();
pServer->setCallbacks (new MyServerCallbacks ());
BLEService *pService = pServer->createService (SERVICE_UUID);
pTxCharacteristic = pService->createCharacteristic (CHARACTERISTIC_UUID_TX,
BLECharacteristic::
PROPERTY_NOTIFY);
pTxCharacteristic->addDescriptor (new BLE2902 ());
pService->start ();
pServer->getAdvertising ()->start ();
Serial.println ("Waiting a client connection to notify...");
//BLE Declaration
//ADC Semaphore and Timer Declarations
bin_sem = xSemaphoreCreateBinary ();
bin_sem2 = xSemaphoreCreateBinary ();
if (bin_sem == NULL || bin_sem2 == NULL)
{
Serial.println ("Could not create semaphore");
ESP.restart ();
}
xTaskCreatePinnedToCore (move_to_Queue,
"move_to_Queue", 1024, NULL, 2, NULL, app_cpu);
xTaskCreatePinnedToCore (BLE_Task,
"BLE_Task", 2048, NULL, 2, NULL, app_cpu);
timer = timerBegin (0, timer_divider, true);
// Provide ISR to timer (timer, function, edge)
timerAttachInterrupt (timer, &onTimer, true);
// At what count should ISR trigger (timer, count, autoreload)
timerAlarmWrite (timer, timer_max_count, true);
// Allow ISR to trigger
timerAlarmEnable (timer);
vTaskDelete (NULL);
}
void loop ()
{
// put your main code here, to run repeatedly:
}
`
Whole code: https://pastebin.com/K8ppkG28
Thanks in advance guys

Alternative to global arrays in C multithreading environment?

does anyone know about an elegant (efficient) alternative to using large global arrays in C for an embedded system, whereby the array is written to in an interrupt service routine and it is read elsewhere asynchronously:
I have no issues with the current implementation, however I was just wondering if it is the best option.
for example:
uint8_t array_data[20] = {0};
volatile bool data_ready = false;
someIsr(void){
for(uint8_t i = 0; i < 20; i++){
array_data[i] = some_other_data[i];
}
data_ready = true;
}
main(void){
for(;;){
if(data_ready){
write_data_somewhere(&array_data[0]);
data_ready = false;
}
}
}
Thanks
Using global arrays is often the best approach unless one would need to use the storage for other purposes when the interrupt routine isn't running. An alternative is to use a global pointer to data that may be stored elsewhere, but one must be very cautious changing that pointer while interrupts are enabled.
An important caveat with your code, by the way: although the Standard regards the implications of a volatile qualifier as implementation-defined, allowing for the possibility that implementations may treat a volatile write as a potential "memory clobber", the authors of gcc require the use of compiler-specific intrinsics to prevent operations on "ordinary" objects from being reordered across operations on volatile-qualified ones.
For example, given:
volatile unsigned short out_count;
int *volatile out_ptr;
int buffer[10];
__attribute__((noinline))
void do_write(int *p, unsigned short count)
{
__asm("");
out_ptr = p;
out_count = count;
do {} while(out_count);
__asm("");
}
void test(void)
{
buffer[0] = 10;
buffer[1] = 20;
do_write(buffer, 2);
buffer[0] = 30;
buffer[1] = 40;
buffer[2] = 50;
do_write(buffer, 3);
}
because the __asm intrinsics don't use gcc-specific syntax to indicate that they might "clobber" the contents of memory in ways the compiler can't understand (even though many compilers support the use of empty __asm intrinsics for that express purpose, and such intrinsics wouldn't really serve any other purpose), and because gcc can see that there's no way that do_write could alter the contents of buffer, it "optimizes out" the code that would store the values 10 and 20 into buffer before the first call to do_write.
Clang doesn't seem quite as bad as gcc. It doesn't seem to reorder writes across volatile writes, it seems to refrain from reordering reads across functions that are not in-line expanded, and it seems to treat empty asm directives as potential memory clobbers, but I I'm not familiar enough with its documentation to know whether such restraint is by design, or merely a consequence of "missed optimizations" which might be "fixed" in future versions.
Consider using translation unit scope rather than global scope. That is declare the array static in the translation unit in which it is used. That translation unit should contain in this case the ISR that writes the data and an access function to read the data. Anything else, including main() should be in other translation units in order that that do not have direct access to the array:
#include <stdbool.h>
#include <stdint.h>
static volatile uint8_t array_data[DATA_LEN] = {0};
static volatile bool data_ready = false;
void someIsr(void)
{
for(uint8_t i = 0; i < 20; i++)
{
array_data[i] = some_other_data[i];
}
data_ready = true;
}
bool getdata( char* dest )
{
bool new_data = data_ready ;
if( data_ready )
{
memcpy( desr, array_data, sizeof(array_data) ) ;
data_ready = false ;
}
}
Then main() in some other translation unit might have:
#include "mydevice.h"
int main( void )
{
uint8_t somewhare[DATA_LEN] = {0};
for(;;)
{
if( getdata( somewhere ) )
{
// process new data
}
}
}
The above is based on your example, and the aim here is to isolate the array so that outside of the ISR the access is enforced to be read-only. In practice it is likely that you will need a "safer" data structure or access method such as a critical-section, double-buffering or a ring buffer so that the data can be accessed without risk of it being modified while it is being read.
This is no less efficient that your original global access, it is simply a restriction of the visibility and accessibility of the array.
As I mentioned in my top comment, one of best ways is to implement a ring queue.
Although I done a few ring queue implementations, here's one I just cooked up for illustration purposes. It is a [cheap] simulation of an Rx ISR for a uart [which is fairly common in embedded systems].
It is fairly complete, but I've not debugged it, so it may have some issues with the queue index calculations.
Anyway, here's the code:
// queue.c -- a ring queue
#include <stdlib.h>
#include <unistd.h>
enum {
QMAX = 1024
};
typedef unsigned char qdata_t; // queue data item
typedef struct {
int qenq; // index for enqueue
int qdeq; // index for dequeue
int qmax; // maximum number of elements in queue
int qover; // number of queue overflows
qdata_t *qbuf; // pointer to queue's buffer
} queue_t;
queue_t *rxisr_q; // pointer to Rx qeueue
// cli -- disable interrupts
void
cli(void)
{
}
// sti -- enable interrupts
void
sti(void)
{
}
// uart_ready -- uart is ready (has Rx data available)
int
uart_ready(void)
{
int rval = rand();
rval = ((rval % 100) > 95);
return rval;
}
// uart_getc -- get character from uart receiver
int
uart_getc(void)
{
int rval = rand();
rval &= 0xFF;
return rval;
}
// qwrap -- increment and wrap queue index
int
qwrap(queue_t *que,int qidx,int inc)
{
int qmax = que->qmax;
qidx += inc;
if (inc > 0) {
if (qidx >= qmax)
qidx -= qmax;
}
else {
if (qidx < 0)
qidx += qmax;
}
return qidx;
}
// qavail_total -- total amount of space available (for enqueue)
int
qavail_total(queue_t *que)
{
int qlen;
qlen = que->qdeq - que->qenq;
if (qlen < 0)
qlen += que->qmax;
qlen -= 1;
return qlen;
}
// qavail_contig -- total amount of space available (for enqueue) [contiguous]
int
qavail_contig(queue_t *que)
{
int qlen;
qlen = que->qdeq - que->qenq;
if (qlen < 0)
qlen = que->qmax - que->qenq;
qlen -= 1;
return qlen;
}
// qready_total -- total amount of space filled (for dequeue)
int
qready_total(queue_t *que)
{
int qlen;
qlen = que->qenq - que->qdeq;
if (qlen < 0)
qlen += que->qmax;
return qlen;
}
// qready_contig -- total amount of space filled (for dequeue) [contiguous]
int
qready_contig(queue_t *que)
{
int qlen;
qlen = que->qenq - que->qdeq;
if (qlen < 0)
qlen = que->qmax - que->qdeq;
return qlen;
}
// qfull -- is queue full?
int
qfull(queue_t *que)
{
int next;
next = qwrap(que,que->qenq,1);
return (next == que->qdeq);
}
// qpush -- push single value
int
qpush(queue_t *que,qdata_t chr)
{
int qenq = que->qenq;
int qnxt;
int push;
qnxt = qwrap(que,qenq,1);
push = (qnxt != que->qdeq);
if (push) {
que->qbuf[qenq] = chr;
que->qenq = qnxt;
}
return push;
}
// qalloc -- allocate a queue
queue_t *
qalloc(int qmax)
{
queue_t *que;
que = calloc(1,sizeof(*que));
que->qbuf = calloc(qmax,sizeof(qdata_t));
return que;
}
// uart_rx_isr -- ISR for uart receiver
void
uart_rx_isr(void)
{
int chr;
queue_t *que;
que = rxisr_q;
while (uart_ready()) {
chr = uart_getc();
#if 0
if (qfull(que)) {
++que->qover;
break;
}
#endif
if (! qpush(que,chr)) {
++que->qover;
break;
}
}
}
int
main(int argc,char **argv)
{
int qlen;
int qdeq;
queue_t *que;
rxisr_q = qalloc(QMAX);
que = rxisr_q;
while (1) {
cli();
qlen = qready_contig(que);
if (qlen > 0) {
qdeq = que->qdeq;
write(1,&que->qbuf[qdeq],qlen);
que->qdeq = qwrap(que,qdeq,qlen);
}
sti();
}
return 0;
}

Struct memory allocation issues for message buffer

I'm trying to use static structs as a buffer for incoming messages, in order to avoid checking the buffer on the MCP2515-external unit. An ISR enters the function with a can_message* value 255 to actually read new messages from my MCP2515.
Other applications register an ID in the message passed as argument, in order to check if the buffer holds any messages with the same value.
This returns wrong IDs, and the rest of the datafields are 0 and uninitialized. What is wrong?
can_message struct:
typedef struct
{
uint8_t id;
uint8_t datalength;
uint8_t data[8];
}can_message;
int CAN_message_receive(can_message* message)
{
static volatile can_message* buffers = (volatile can_message*)0x18FF;
static int birth = 1;
if(birth)
{
for (int i; i < CAN_MESSAGE_UNIQUE_IDS; i++)
{
//These structs gets addresses outside SRAM
buffers[i] = (can_message){0,0,0};
}
birth = 0;
}
if (message == CAN_UPDATE_MESSAGES)
{
/* Sorts messages <3 */
can_message currentMessage;
//These functions are working:
CAN_message_get_from_MCP_buf(&currentMessage, 0);
buffers[currentMessage.id] = currentMessage;
CAN_message_get_from_MCP_buf(&currentMessage, 1);
buffers[currentMessage.id] = currentMessage;
return 0; //returns nothing !
}
if(buffers[message->id].id != 0)
{
printf("test\n");
//This copy gives wrong id and data:
memcpy(message, &buffers[message->id], sizeof(can_message));
buffers[message->id].id = 0;
return 0;
}
return -1;
}
Edit 1:
I did however notice that any buffers[i]-struct gets a totally different address than expected. It does not use the addresses following 0x18FF on the SRAM. Is there any way to change this?
Edit 2:
This is my main-loop:
while (1) {
//printf("tx buf ready: %d\n", MCP2515_TX_buf_empty(0));
//CAN_Loopback_test();
_delay_ms(500);
value = USART_ReadByte(0);
CAN_message_receive(&msg);
printf("CAN_receive: ID: %d, datalength: %d, data: \n",msg.id);
for (int k; k < msg.datalength; k++)
{
printf("%d, ",msg.data[k]);
}
printf("\n");
}
Edit 3: Changing the buffer-pointer to array solved the issue. (It does no longer use the SRAM, but whatever floats my boat)
int CAN_message_receive(can_message* message)
{
static can_message buffers[CAN_MESSAGE_UNIQUE_IDS];
static int birth = 1;
if(birth)
{
for (int i; i < CAN_MESSAGE_UNIQUE_IDS*10; i++)
{
*(char*)(0x18FF+i) = 0;
printf("buffers: %X\n", &buffers[i]);
}
birth = 0;
}
Solved!
Pointer to buffers changed to buffer-array:
int CAN_message_receive(can_message* message)
{
static can_message buffers[CAN_MESSAGE_UNIQUE_IDS];
static int birth = 1;
if(birth)
{
for (int i; i < CAN_MESSAGE_UNIQUE_IDS*10; i++)
{
*(char*)(0x18FF+i) = 0;
printf("buffers: %X\n", &buffers[i]);
}
birth = 0;
}
I would strongly suggest to decouple the ISR logic with the programs own message cache logic. Also the initializing logic with the birth variable looks unnecessary.
I would setup some ring buffer that the ISR can write messages to and from that the main code reads the data into the ID-lookup-buffer.
This would ensure that message updates does not interfere with readouts (at least if you check the read/write indices to your ring buffer) and also eliminates the need to put Mutexes around your whole message buffer.
Currently it smells very badly because of missing read/write synchronization.
// global
#define CAN_MESSAGE_UNIQUE_IDS 50
static can_message g_can_messagebuffers[CAN_MESSAGE_UNIQUE_IDS];
#define MAX_RECEIVEBUFFER 8
static volatile can_message g_can_ringbuffer[MAX_RECEIVEBUFFER];
static volatile int g_can_ringbufferRead = 0;
static volatile int g_can_ringbufferWrite = 0;
// called from ISR
void GetNewMessages()
{
// todo: check ring buffer overflow
can_message currentMessage;
CAN_message_get_from_MCP_buf(&g_can_ringbuffer[g_can_ringbufferWrite], 0);
g_can_ringbufferWrite = (g_can_ringbufferWrite + 1) % MAX_RECEIVEBUFFER;
CAN_message_get_from_MCP_buf(&g_can_ringbuffer[g_can_ringbufferWrite], 1);
g_can_ringbufferWrite = (g_can_ringbufferWrite + 1) % MAX_RECEIVEBUFFER;
}
// called from main loop
void handleNewMessages()
{
while(g_can_ringbufferRead != g_can_ringbufferWrite){
const can_message* currentMessage = &g_can_ringbuffer[g_can_ringbufferRead];
if(currentMessage->id < CAN_MESSAGE_UNIQUE_IDS)
{
g_can_messagebuffers[currentMessage->id] = *currentMessage;
}
g_can_ringbufferRead = (g_can_ringbufferRead + 1) % MAX_RECEIVEBUFFER;
}
}
// called from whoever wants to know
// todo:
// really required a by value interface?
// would it not be sufficient to return a pointer and
// provide an additional interface to mark the message as used?
int getMsg(can_message* message)
{
if(buffers[message->id].id != 0)
{
printf("test\n");
*message = &g_can_messagebuffers[message->id];
g_can_messagebuffers[message->id].id = 0;
return 0;
}
return -1;
}
// alternative to above
const can_message* getMsg(int id)
{
if( (id < CAN_MESSAGE_UNIQUE_IDS)
&& (g_can_messagebuffers[id] != 0))
{
return &g_can_messagebuffers[id].id;
}
return NULL;
}
void invalidateMsg(int id)
{
if(id < CAN_MESSAGE_UNIQUE_IDS)
{
g_can_messagebuffers[id] = 0;
}
}
edit:
after your changes to an message array instead some strange pointer, there is also no need for the setup routine for this code.
edit:
if your micro controller already has a buffer for received messages, then may be it is unnecessary at all to register a ISR and you could empty it from the mainloop directly into your own id-lookup buffer (assuming the mainloop is fast enough)

kprobe, function scheduling - processor lockup - Linux kernel

I've a function I wrote in order to run a given function on all processors. It works perfectly well in all cases except the following case:
When I try to use it within a kprobe that I registered.
Here's some code:
static DEFINE_MUTEX(entryMutex);
static struct kretprobe my_kprobe = {
.entry_handler = (kprobe_opcode_t *) NULL,
.handler = (kprobe_opcode_t *) process_entry_callback,
.maxactive = 1000,
.data_size = 0
};
static int driver_init(void)
{
my_kprobe.kp.addr = (kprobe_opcode_t*)kallsyms_lookup_name("sys_execve");
if ((ret = register_kretprobe(&my_kprobe)) < 0)
return -1;
return 0;
}
void foo(void* nothing)
{
printk("In foo\n");
}
static int process_entry_callback(struct kretprobe_instance* instance, struct pt_regs* regs)
{
mutex_lock(&entryMutex);
for(int i = 0; i < 4; ++i) // assumes there are 4 processors
run_func(foo, NULL, i);
mutex_unlock(&entryMutex);
return 0;
}
void run_func_wrap(struct function_data* data)
{
data->func(data->context);
wake_up_process(data->waiting_task);
*(data->condition) = TRUE;
}
void run_func(SCHEDULED_FUNC func, void *context, int processor)
{
struct function_data data;
struct task_struct* th;
BOOLEAN condition = FALSE;
wait_queue_head_t queue;
init_waitqueue_head(&queue);
data.func = func;
data.waiting_task = current;
data.context = context;
data.condition = &condition;
th = kthread_create(sched_func_wrap, &data, "th");
kthread_bind(th, processor);
wake_up_process(th);
wait_event(queue, condition);
}
F
After the call to 'run_func' in process_entry_callback I can no longer run any programs. Every time I start a new program it just stuck. After a while I get 'processor lockup' warning in the system log.
I suspect that it has something to do with the IRQ levels.
Any suggestions ?
EDIT:
It also happens when using the following function:
smp_call_function_single
which can be found in smp.c # the Linux kernel source code.
instead of my function:
run_func

User level thread

I am trying to create user level thread. Here is a sample of my code. Can any body help me what is the problem in this program.
#include<stdio.h>
#include<ucontext.h>
int thread_counter = 0;
int thread1, thread2;
int who_am_i;
struct TCB {
ucontext_t context;
void (* fun_ptr)();
};
struct TCB tcb[3];
char stack[2][8192];
//----------------------
int thread_create(void (*fun)()) {
static volatile int s;
thread_counter++;
s = 0;
getcontext(&tcb[thread_counter].context);
if(!s) {
tcb[thread_counter].context.uc_stack.ss_sp = stack[thread_counter];
tcb[thread_counter].context.uc_stack.ss_size = sizeof(stack[thread_counter]);
tcb[thread_counter].context.uc_link = &tcb[0].context;
tcb[thread_counter].fun_ptr = fun;
s = 1;
}
else {
tcb[who_am_i].fun_ptr();
}
return thread_counter;
}
void thread_yield(int next_thread) {
static volatile int switched;
switched = 0;
getcontext(&tcb[who_am_i].context);
if(!switched) {
switched = 1;
who_am_i = next_thread;
setcontext(&tcb[next_thread].context);
}
}
//----------------------
void f1() {
printf("start f1\n");
thread_yield(thread2);
printf("finish f1:\n");
}
void f2() {
printf("start f2\n");
thread_yield(thread1);
printf("finish f2\n");
}
//----------------------
int main() {
thread1 = thread_create(f1);
thread2 = thread_create(f2);
who_am_i = 0;
thread_yield(thread1);
return 0;
}
Thread is not switching properly. When I run it, it gives following output:
start f1
start f2
finish f2
Thank you
You have an undefined behavior situation.
In thread_create you increase thread_counter the first thing you do. So when you create the second thread thread_counter will be 2. Then you access stack[2] which will give you undefined behavior.
You also hardcode the uc_link member of the context to &tcb[0].context, which is never initialized due to your "premature" increment of thread_counter.
But the main problem is that you don't actually create a new context, you just get the context for the current thread. You should use makecontext for each thread instead.

Resources