Linux Kernel: Ununderstood behaviour of read-write lock rwlock (Deadlock) - linux-kernel

Experimenting with (linux kernel) rwlock API, and I'm getting a behavior (deadlock) that I cannot understand why it s happening.
Does someone have some explanation? (Please note the code is just for experiments no
logic behind: example I know that it is a bad idea to sleep while holding a spinlock but that
has no effect on the code I testing).
The Code is the following, and running results in a deadlock.
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/kthread.h>
#include <linux/sched.h>
#include <linux/spinlock.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("<toto#gmail.com>");
MODULE_DESCRIPTION("test rwlock");
static DEFINE_RWLOCK(rwlock);
// shared variable
static int var;
static struct task_struct *w;
static struct task_struct *r1;
static struct task_struct *r2;
static int w_f(void *unsed)
{
while (1) {
printk("w: try to lock\n");
if (write_trylock(&rwlock)) {
printk("w: locked\n");
} else {
printk("w: unavailable lock, spin\n");
write_lock(&rwlock);
printk("w: out of spin\n");
}
var = 1;
ssleep(4);
write_unlock(&rwlock);
printk("w: write unlock\n");
if (kthread_should_stop()) {
printk("w: should stop now\n");
return 1;
} else {
printk("w: continue...\n");
}
}
return 1;
}
static int r1_f(void *unsed)
{
while (1) {
if (read_trylock(&rwlock)) {
printk("\tr1: locked\n");
ssleep(3);
printk("\tr1: read access\n");
read_unlock(&rwlock);
} else {
printk("\tr1: unavailbe lock, spin\n");
read_lock(&rwlock);
}
if (kthread_should_stop()) {
printk("\tr1: should stop now\n");
return 1;
} else {
printk("\tr1: continue...\n");
}
}
return 0;
}
static int r2_f(void *unsed)
{
while (1) {
if (read_trylock(&rwlock)) {
printk("\tr2: locked\n");
ssleep(1);
printk("\tr2: read access\n");
read_unlock(&rwlock);
} else {
printk("\tr2: unavailbe lock, spin\n");
read_lock(&rwlock);
}
if (kthread_should_stop()) {
printk("\tr2: should stop now\n");
return 1;
} else {
printk("\tr2: continue...\n");
}
}
return 0;
}
static int __init init_thread(void)
{
printk(KERN_ALERT "Thread creating ...\n");
w = kthread_create(w_f, NULL, "writer1");
r1 = kthread_create(r1_f, NULL, "reader1");
r2 = kthread_create(r2_f, NULL, "reader2");
if (w && r1 && r2) {
printk(KERN_ALERT "Thread Created Sucessfully\n");
wake_up_process(w);
wake_up_process(r1);
wake_up_process(r2);
} else {
printk("Thread Creation Failed\n");
}
return 0;
}
static void __exit cleanup_thread(void)
{
int ret, ret1, ret2;
printk(KERN_ALERT "Cleaning up ...\n");
ret = kthread_stop(w);
ret1 = kthread_stop(r2);
ret2 = kthread_stop(r2);
printk("stop threads returned %d,%d,%d\n", ret, ret1, ret2);
}
module_init(init_thread)
module_exit(cleanup_thread)
I'm getting the log:
[0 291.18289] Thread creating ...
[0 291.18444] Thread Created Sucessfully
[0 291.18450] w: try to lock
[0 291.18453] r1: locked
[0 291.18456] r2: locked
[0 291.18459] w: unavailable lock, spin
[1 292.261093] r2: read access
[1 292.261096] r2: continue...
[1 292.261096] r2: unavailbe lock, spin
[3 294.261151] r1: read access
[3 294.261153] r1: continue...
[3 294.261167] w: out of spin
[3 294.261168] r1: unavailbe lock, spin
[7 298.265307] w: write unlock
[7 298.265308] r1: continue...
[7 298.265308] r2: continue...
[7 298.265309] r1: locked
[7 298.265309] r2: locked
[7 298.265314] w: continue...
[7 298.265314] w: try to lock
[7 298.265315] w: unavailable lock, spin
[8 299.269282] r2: read access
[8 299.269285] r2: continue...
[8 299.269286] r2: unavailbe lock, spin
[10 301.269377] r1: read access
[10 301.269380] r1: continue...
[10 301.269381] r1: unavailbe lock, spin
[33 324.122110] **NMI watchdog: BUG: soft lockup - CPU#2 stuck for 22s! [writer1:3819]**
I tried to schematize the runtime:
(----) -> running(ssleep) holding the lock.
(====) -> spinning on the lock
time 0 1 2 3 4 5 6 7 8 9 10 11 12 33
r1 *-----+-----+-----+=====+=====+=====+=====+-----+-----+-----+=====+=====+===== ... +=====+=====
r2 *-----+=====+=====+=====+=====+=====+=====+-----+=====+=====+=====+=====+===== ... +=====+=====
w *=====+=====+=====+-----+-----+-----+-----+=====+=====+=====+=====+=====+===== ... +=====+=====
The ununderstood behavior:
I m wondering why (w) thread keeps spinning at 10s, the situation is identical to instant 3s: r2 is spinning, because w tried to acquire the write lock (w is spinning as r1 holds the lock), but when r1 is done, w should get unlocked and starts running. This happens at 3s but not at 10s.

Yes fixed.
static int w_f(void *unsed)
{
while (1) {
printk("w: try to lock\n");
if (write_trylock(&rwlock)) {
printk("w: locked\n");
} else {
printk("w: unavailable lock, spin\n");
write_lock(&rwlock);
printk("w: out of spin\n");
}
var = 1;
ssleep(4);
write_unlock(&rwlock);
printk("w: write unlock\n");
if (kthread_should_stop()) {
printk("w: should stop now\n");
return 1;
} else {
printk("w: continue...\n");
}
}
return 1;
}
static int r1_f(void *unsed)
{
while (1) {
if (read_trylock(&rwlock)) {
printk("\tr1: locked\n");
} else {
printk("\tr1: unavailbe lock, spin\n");
read_lock(&rwlock);
}
ssleep(3);
printk("\tr1: read access\n");
read_unlock(&rwlock);
if (kthread_should_stop()) {
printk("\tr1: should stop now\n");
return 1;
} else {
printk("\tr1: continue...\n");
}
}
return 0;
}
static int r2_f(void *unsed)
{
while (1) {
if (read_trylock(&rwlock)) {
printk("\tr2: locked\n");
} else {
printk("\tr2: unavailbe lock, spin\n");
read_lock(&rwlock);
}
ssleep(1);
printk("\tr2: read access\n");
read_unlock(&rwlock);
if (kthread_should_stop()) {
printk("\tr2: should stop now\n");
return 1;
} else {
printk("\tr2: continue...\n");
}
}
return 0;
}
static int __init init_thread(void)
{
printk(KERN_ALERT "Thread creating ...\n");
w = kthread_create(w_f, NULL, "writer1");
r1 = kthread_create(r1_f, NULL, "reader1");
r2 = kthread_create(r2_f, NULL, "reader2");
if (w && r1 && r2) {
printk(KERN_ALERT "Thread Created Sucessfully\n");
wake_up_process(w);
wake_up_process(r1);
wake_up_process(r2);
} else {
printk("Thread Creation Failed\n");
}
return 0;
}
static void __exit cleanup_thread(void)
{
int ret, ret1, ret2;
printk(KERN_ALERT "Cleaning up ...\n");
ret = kthread_stop(w);
ret1 = kthread_stop(r2);
ret2 = kthread_stop(r2);
printk("stop threads returned %d,%d,%d\n", ret, ret1, ret2);
}
module_init(init_thread)
module_exit(cleanup_thread)

Related

How do I turn off my void loop function after a certain IF condition is met? (arduino)

I am trying to make a simple burglar alarm using magnet value as my door. After pressing button1 it goes into countdown and then the user should be able to press button1 again to insert a 3 digit code with the help of pmeter. Except that after button1 is clicked it calls toggleOnOff() again. How do I block my void toggleOnOff() function after the conditions of the first IF statement are met? Thank you in advance.
int startMagnetValue;
int Code[3] = {1, 2, 3};
int userCode[3] = {0, 0, 0};
int secondsLimit = 20;
int countDown;
int pMeter = 0;
int pMin = 14;
int pMax = 948;
unsigned long time_now = 0;
unsigned long time_then = 0;
unsigned long seconds = 0;
unsigned long secondsbefore = 1;
unsigned long interval = 1000;
void setup() {
initializeBreadboard();
startMagnetValue = analogRead(MAGNETSENSOR);
}
//turns off leds
void turnOffLEDS() {
digitalWrite(LED_RED, LOW);
digitalWrite(LED_BLUE, LOW);
digitalWrite(LED_YELLOW, LOW);
digitalWrite(LED_GREEN, LOW);
}
// returns true when the difference is bigger than 50, returns false when it's less than 50. True meaning door is open and False meaning it is closed
bool isOpen(int magnetValue) {
int magnetValueDifference = abs(startMagnetValue - magnetValue);
if (magnetValueDifference <= 50) {
return true;
} else {
return false;
}
}
//Toggles the alarm On or Off
void toggleOnOff() {
isAlarmOn = !isAlarmOn;
delay(200);
}
//registers if the alarm is on or off, also prints current magnet value to the oled
void loop() {
pMeter = analogRead(POTENTIOMETER);
int currentMagnetValue = analogRead(MAGNETSENSOR);
pMeter = map(pMeter, pMin, pMax, 0, 9); //translates pmeter to simple digits
OLED.printBottom(pMeter);
Serial.println(userCode[1]);
//On Off
if (digitalRead(BUTTON1)) {
toggleOnOff();
}
// Door Open, Alarm On
if(isOpen(currentMagnetValue) && isAlarmOn) {
turnOffLEDS();
digitalWrite(LED_RED, HIGH);
OLED.printTop(secondsLimit);
time_now = millis();
while((time_now - time_then) >= 1000)
{ secondsLimit--;
time_then = time_now;
Serial.println(secondsLimit);
}
if (userCode[1] = 0) {
if (digitalRead(BUTTON1)) {
userCode[1] = pMeter;
}
}
if (userCode[2] = 0) {
if (digitalRead(BUTTON1)) {
userCode[2] = pMeter;
}
}
if (userCode[3] = 0) {
if (digitalRead(BUTTON1)) {
userCode[3] = pMeter;
}
}
if (Code == userCode) {
isAlarmOn = false;
}
if (secondsLimit <= 0) {
digitalWrite(BUZZER, HIGH);
turnOffLEDS();
while (secondsLimit <= 0) {
OLED.print("INTRUDER");
turnOffLEDS();
digitalWrite(LED_RED, HIGH);
delay(100);
turnOffLEDS();
digitalWrite(LED_BLUE, HIGH);
delay(100);
turnOffLEDS();
digitalWrite(LED_YELLOW, HIGH);
delay(100);
turnOffLEDS();
digitalWrite(LED_GREEN, HIGH);
}
}
} else if (isOpen(currentMagnetValue) && !isAlarmOn) {
turnOffLEDS();
digitalWrite(LED_BLUE, HIGH);
//Door closed, Alarm On
} else if (!isOpen(currentMagnetValue) && isAlarmOn) {
turnOffLEDS();
digitalWrite(LED_GREEN, HIGH);
//Door closed, Alarm Off
} else if (!isOpen(currentMagnetValue) && !isAlarmOn) {
turnOffLEDS();
digitalWrite(LED_YELLOW, HIGH);
}
}```

How to exit or break from 'for loop' on Arduino C Program

I'm not new to the programming world, but for last 2 weeks I'm working with Arduino C++. I have a strange problem. In general, I have a 7-segment display that will act as an up counter when the condition is 01, down counter when the condition is 10, 00 for reset to zero, and 11 for stop (pause in that number).
The problem is, when the up or down counter is still counting and I've change the state, the 7-segment is still counting! Besides that, I've printed the status of state when state is changed, but nothing happens. I think maybe there's mistakes in my code, I need some advice from you guys. Here is my code:
*FYI, I've try to use break, return, also call loop(), but nothing happens
*saklar1 = switch1
*saklar2 = switch2
#include <SevSeg.h>
SevSeg sevseg;
const int saklar1 = 2;
const int saklar2 = 3;
void setup() {
byte sevenSegments = 1;
byte commonPins[] = {};
byte sevenPins[] = {11, 10, 9, 8, 7, 6, 5, 4};
bool resistor = true;
sevseg.begin(COMMON_CATHODE, sevenSegments, commonPins, sevenPins, resistor);
sevseg.setBrightness(90);
pinMode(saklar1, INPUT);
pinMode(saklar2, INPUT);
Serial.begin(9600);
}
void loop() {
checking(digitalRead(saklar1), digitalRead(saklar2));
}
void checking(bool saklar1, bool saklar2){
if (saklar1 == LOW && saklar2 == LOW) {
setSevSeg(0);
} else if (saklar1 == LOW && saklar2 == HIGH) {
for (int i=0; i<=9; i++) {
setSevSeg(i);
if (saklar1 != LOW || saklar2 != HIGH) {
Serial.println("STATE CHANGED"); //THIS LINE IS NOT EXECUTED OR PRINTED
checking(digitalRead(saklar1), digitalRead(saklar2));
}
}
} else if (saklar1 == HIGH && saklar2 == LOW) {
for (int i=9; i>=0; i--) {
setSevSeg(i);
if (saklar1 != HIGH || saklar2 != LOW) {
checking(digitalRead(saklar1), digitalRead(saklar2));
}
}
} else if (saklar1 == HIGH && saklar2 == HIGH) {
delay(100); //Stop
}
}
void setSevSeg(int num) {
sevseg.setNumber(num);
sevseg.refreshDisplay();
delay(500); //1 detik
}
In the following code, the control exits the for loop when the sensor value exceeds the threshold.
Reference: [https://www.arduino.cc/reference/en/language/structure/control-structure/break]
int threshold = 40;
for (int x = 0; x < 255; x++) {
analogWrite(PWMpin, x);
sens = analogRead(sensorPin);
if (sens > threshold) { // bail out on sensor detect
x = 0;
break;
}
delay(50);
}

How to generate soft lockup in preemptive kernel?

I have enabled CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC in kernel configuration, now I want to test this behavior that kernel should panic in case of softlockup,
To try this I have created one module,
int thread_function(void *data)
{
int var;
var = 10;
printk(KERN_INFO "Inside %s %s\n",STR_MOD,__func__);
//while(!kthread_should_stop()){
while(1) {
printk(KERN_INFO "Mutiplying...\n");
var = var*var*var; //test
}
//}
return var;
}
static int kernel_init(void)
{
data = 20;
printk(KERN_INFO"insmod %s\n",STR_MOD);
/*task = kthread_create(&thread_function,(void *)data,"SD");*/
task = kthread_run(&thread_function,(void *)data,"SD");
set_cpus_allowed(task, *cpumask_of(0));
printk(KERN_INFO"Kernel Thread : %s\n",task->comm);
return 0;
}
With this CPU 0 is busy processing task and reports ~99.9% usage with top
but it is not generating softlockup.
So, my question is how can I achieve this?

Omnet ++ sending message from specific node to other specific node

following is my .ned file of the network of 3 nodes
simple computer
{
parameters:
gates:
input in1;
output out1;
input in2;
output out2;
}
//
// TODO documentation
//
network Network
{
#display("bgb=538,302");
submodules:
A: computer {
#display("p=30,88");
}
B: computer {
#display("p=344,96");
}
C: computer {
#display("p=209,199");
}
connections:
A.out1 --> B.in1;
B.out1 --> A.in1;
A.out2 --> C.in1;
C.out1 --> A.in2;
C.out2 --> B.in2;
B.out2 --> C.in2;
}
#include <string.h>
#include <omnetpp.h>
#include <string>
int a2b=8; int b2a=8;
int b2c=2; int c2b=2;
int a2c=5; int c2a=5;
char node='x';
int roundd=0;
char rec='A';
int Amatrix[3][3];
int Bmatrix[3][3];
int Cmatrix[3][3];
class computer: public cSimpleModule
{
public:
virtual void initialize();
virtual void handleMessage(cMessage *msg);
void fill()
{
for(int i=0 ; i<3 ; i++)
{
for(int j=0 ; j<3 ; j++)
{
Amatrix[i][j]=Bmatrix[i][j]=Cmatrix[i][j]=0;
}
}
}
void fillA()
{
Amatrix[0][0]=0;Amatrix[0][1]=a2b;Amatrix[0][2]=a2c;
}
void fillB()
{
Bmatrix[1][0]=a2b;Bmatrix[1][1]=0;Bmatrix[1][2]=b2c;
}
void fillC()
{
Cmatrix[2][0]=a2c;Cmatrix[2][1]=b2c;Cmatrix[2][2]=0;
}
};
//----------------------------------------------------------------------
Define_Module(computer);
void computer::initialize()
{
if ((strcmp("A", getName()) == 0)&&(roundd==0))
{
node='A';
fill();
fillA();fillB(); fillC(); roundd=1;node='A';
cMessage *msg = new cMessage("tictocMsg");
cMessage *ww ; ww=msg;
EV << "sending message from node " << node ;
send(msg, "out1");
cMessage *copy = (cMessage *) msg->dup();
send(copy, "out2");
}
}
void computer::handleMessage(cMessage *msg)
{
if((strcmp("B", getName()) == 0 )&&(roundd=1)&&(node=='A'))
{
rec='B';
EV <<"\n NODE AT WHICH THE MESSAGE IS AT CURRENTLY IS " << rec <<endl;
for(int i=0 ; i<3 ; i++)
{
Bmatrix[0][i]=Amatrix[0][i];
}
}
else if((strcmp("C", getName()) == 0)&&(node=='A')&&(roundd==1))
{
rec='C';
EV <<"\n NODE AT WHICH THE MESSAGE IS AT CURRENTLY IS " << rec <<endl;
for(int i=0 ; i<3 ; i++)
{
Cmatrix[0][i]=Amatrix[0][i];
}
roundd=2;
}
if(roundd==2)
{
if((strcmp("C", getName()) == 0 )){EV << " node c ";}
if((strcmp("B", getName()) == 0 )){EV << " node B ";}
}}
Now in the roundd 2
if(roundd==2)
{
if((strcmp("C", getName()) == 0 )){EV << " node c ";}
if((strcmp("B", getName()) == 0 )){EV << " node B ";}
}}
the first if works where strcmp is "C". but the second if does not. I actually want node B to send two messages to node A and C afterwards i want to send messages from c to A and c to B. Basically at initialize A send two messages, one to B and one to C. Now i want to send message from B to A and B to C
similarly from C to A and C to B how do i do that?

Why i am not able to read multiple strings in the server file?

While working in client-server programming, I have passed 3 strings in client, which will be received by server and it should be printed in there 3 times. (i.e I have used a 'for' loop which will do the read & write operations in client & server side respectively.), but in server only the 1st string is getting printed.
Please explain,
Here is my code
server.c
#include "head.h"
void readstr(int connfd ,char [][20]);
//void writestr(char * ,int);
int main(int c ,char *v[])
{
// socket declarations,etc
sd =socket( AF_INET ,SOCK_STREAM ,0);
// Binding socket
retbind =bind(sd ,(struct sockaddr*)&serveraddress ,sizeof(serveraddress
));
listen(sd ,4);
for(;;)
{
printf("i am waiting for client\n");
len =sizeof(cliaddr);
connfd = accept(sd ,(struct sockaddr*)&cliaddr ,&len);
readstr(connfd ,databuf);
close(connfd);
}
return 0;
}
void readstr(int connfd ,char str[3] [20])
{
int pointer=0 ,i=0, n,pos=0;
memset(str ,'\0',sizeof(str));
for(i=0;i<3;i++)
{
while((n=read(connfd ,str[i] ,20)) >>0)
{
printf("Looping while\n");
pos =pos +n;
}
str[i][pos] ='\0';
}
for(i=0;i<3;i++)
{
printf("\n%s",str[i]);
}
}
client.c
#include "head.h"
void send1(int ,char*);
int main(int c,char*v[])
{
//Socket declarations, etc..
sd = socket(AF_INET ,SOCK_STREAM ,0);
//Connect
if(connect(sd,(struct sockaddr*)&serveraddress ,sizeof(serveraddress)) <
0)
{
printf("cannot connect to server");
exit(1);
}
for(i=0;i<3;i++)
{
memset(buf ,'\0',sizeof(buf));
printf("\n Enter the string : ");
fgets(buf[i],20,stdin);
len =strlen(buf[i]);
if(buf[i][len] =='\n')
buf[i][len]='\0';
send1(sd ,(char *)buf);
}
shutdown(sd ,SHUT_WR);
}
void send1(int sd ,char *str)
{
int n ,byteswritten =0, wr;
char buf[1024];
strcpy(buf ,str);
n =strlen(buf);
while(byteswritten < n)
{
printf("\nStarting to write in client side\n");
wr = write(sd , buf+byteswritten ,(n-byteswritten));
byteswritten+=wr;
}
printf("\n string sent %s" ,buf);
}
In server.c in readstr() you are not setting pos to zero before the next for iteration.
Also, there is strange line:
while((n=read(connfd ,str[i] ,20)) >>0)
Note ">>".

Resources