I had download Google breakpad source to do some testing, the demo can work normal on X64 and ARM64, but on MIPS64 it does not generate minidump file and child thread will crash after sys_clone under ExceptionHandler::GenerateDump();
I checked the input address of the child thread, found the address is reduced by 16 bytes, my kernel revision is :
[root#neo7 breakpad-master]# uname -r
3.10.0-514.26.2.ns7.030.mips64el
My test code is :
#include "../src/client/linux/handler/exception_handler.h"
#include <pthread.h>
#include <iostream>
using namespace std;
static bool dumpCallback(const google_breakpad::MinidumpDescriptor &descriptor,
void *context,
bool succeeded)
{
printf("Dump path: %s\n", descriptor.path());
char cmd[512] = {0};
snprintf(cmd, sizeof(cmd), "echo %s > dump_name", descriptor.path());
system(cmd);
return succeeded;
}
void *TestThread(void* arg)
{
int input = *(int*)arg;
int *a = (int *)(NULL);
*a = 1;
}
int main(int argc, char *argv[])
{
google_breakpad::MinidumpDescriptor descriptor("/tmp");
google_breakpad::ExceptionHandler eh(descriptor,
NULL,
dumpCallback,
NULL,
true,
-1);
//crashHare();
pthread_t threadId;
int input = 12;
int ret = pthread_create(&threadId, NULL, TestThread, (void*)&input);
if(ret != 0)
{
cout<< "create thread error"<<endl;
}
cout<<"main thread running"<<endl;
pthread_join(threadId,NULL);
return 0;
}
I add some printf in ./src/client/linux/handler/exception_handler.cc, before sys_clone and after ThreadEntry, the log is :
struct ThreadArgument {
pid_t pid; // the crashing process
const MinidumpDescriptor* minidump_descriptor;
ExceptionHandler* handler;
const void* context; // a CrashContext structure
size_t context_size;
};
ThreadArgument thread_arg;
thread_arg.handler = this;
thread_arg.minidump_descriptor = &minidump_descriptor_;
thread_arg.pid = getpid();
thread_arg.context = context;
thread_arg.context_size = sizeof(*context);
zzzzzzz &thread_arg:f10ee460 (before sys_clone)
const pid_t child = sys_clone(
ThreadEntry, stack, CLONE_FS | CLONE_UNTRACED, &thread_arg, NULL, NULL,
NULL);
zzzzzzz child 23889
int ExceptionHandler::ThreadEntry(void *arg) {
zzzzzzz ThreadEntry
zzzzzzz arg:f10ee450 (child thread)
if the type of thread_arg is a int *, there is no address offset problem. If add prefix static for thread_arg, there is no address offset problem too.
static ThreadArgument thread_arg; /* The same goes for malloc, but malloc is not safe */
zzzzzzz &thread_arg:20030060 (before sys_clone)
const pid_t child = sys_clone(
ThreadEntry, stack, CLONE_FS | CLONE_UNTRACED, &thread_arg, NULL, NULL,
NULL);
zzzzzzz child 22399
int ExceptionHandler::ThreadEntry(void *arg) {
zzzzzzz ThreadEntry
zzzzzzz arg:20030060 (child thread)
And I write an another code to test sys_clone under signal processing function:
#include <errno.h>
#include <fcntl.h>
#include <linux/limits.h>
#include <pthread.h>
#include <sched.h>
#include <signal.h>
#include <stdio.h>
#include <sys/mman.h>
#include <sys/prctl.h>
#include <sys/syscall.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/signal.h>
#include <sys/ucontext.h>
#include <sys/user.h>
#include <ucontext.h>
#include <algorithm>
#include <utility>
#include <vector>
#include "src/third_party/lss/linux_syscall_support.h"
#include "src/common/memory_allocator.h"
using namespace google_breakpad;
unsigned char *stack = NULL;
void my_memset(void* ip, char c, size_t len) {
char* p = (char *) ip;
while (len--)
*p++ = c;
}
struct ThreadArgument {
pid_t pid; // the crashing process
const void* minidump_descriptor;
void* handler;
const void* context; // a CrashContext structure
size_t context_size;
};
int ThreadEntry(void *arg) {
printf("arg:%x\n", arg);
const ThreadArgument *thread_arg = reinterpret_cast<ThreadArgument*>(arg);
printf("thread_arg:%x\n", thread_arg);
return 0;
}
void GenerateDump(int signo) {
static const unsigned kChildStackSize = 16000;
PageAllocator allocator;
uint8_t* stack = reinterpret_cast<uint8_t*>(allocator.Alloc(kChildStackSize));
if (!stack)
return ;
stack += kChildStackSize;
my_memset(stack - 16, 0, 16);
ThreadArgument thread_arg;
thread_arg.handler = (void *) NULL;
thread_arg.minidump_descriptor = (void *) NULL;
thread_arg.pid = getpid();
thread_arg.context = (void *) NULL;
thread_arg.context_size = sizeof(void *);
printf("thread_arg:%x\n", &thread_arg);
const pid_t child = sys_clone(
ThreadEntry, stack, CLONE_FS | CLONE_UNTRACED, &thread_arg, NULL, NULL,
NULL);
printf("child:%d\n", child);
sleep(1);
return ;
}
int main(void)
{
signal(SIGSEGV, GenerateDump);
int *a = (int *)NULL;
*a = 1;
return 0;
}
It works normal:
thread_arg:ffcb9030
child:8447
arg:ffcb9030
thread_arg:ffcb9030
I wonder why passing the contents of the stack as parameters causes this
address mismatch problem in breakpad.
Related
I wrote a c++ code to multithreaded copying a file to another directory in linux. but doesn't work(just it made an empty file in directory).
I don't know what's the problem? I think my tread has no right access to write in the shared file. but don't know what should I do.
It should work when typed in terminal :
$./a.out <file name> <dir> <thread number (default 4)>
This is my code:
/*Multithreads file copier*/
#include <fcntl.h>
#include <pthread.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <sys/sendfile.h>
#include <unistd.h>
#include <cstdio>
char* file;
char* fileout_path;
int fin, fout;
// part of each thread
struct PART{
off_t* offset =0;
size_t size;
};
//multithreading
void *Copy (void * data)
{
struct PART *mypart;
mypart = (struct PART *) data;
//open file to read and write
fin = open(file, O_RDONLY,0);
fout = open(fileout_path, O_WRONLY|O_CREAT, 0644);
unsigned long a = static_cast<unsigned long>(mypart->size);
lseek(fout, a, SEEK_SET); //set offset by size of the part
//use sendfile instead read and write to easier code
sendfile(fin, fout, mypart->offset, mypart->size);
printf("threading....\n");//to know the thread ran
pthread_exit(0);
}
int main(int argc, char *argv[])
{
int threads_number;
if (argv[3]!= NULL)
{
threads_number = atoi(argv[3]);
}
else
{
threads_number = 4;//default thread number
}
//multithreading datatypes
pthread_t tid[threads_number];
pthread_attr_t attr;
pthread_attr_init(&attr);
struct stat f_stat;
struct PART part[threads_number];
//allocation size of each part
unsigned long part_size = f_stat.st_size / threads_number;
for(int i =0; i <number_threads; i++)
{
if ( i == threads_number -1)
{
part[threads_number].size = f_stat.st_size - (part_size * (threads_number -1));
}
else
{
part[i].size = part_size;
}
}
file = argv[1];
stat(file, &f_stat);
fileout_path = argv[2];
int fin1 = open(file, O_RDONLY,0);
int fout1 = open(fileout_path, O_WRONLY|O_CREAT, 0644);
for (int j = 0; j < threads_number; j++)
{
pthread_create(&tid[j], NULL, Copy, (void *)&part[j]);
pthread_join(tid[j],NULL);
}
printf("thread is done.\n");
close(fout);
close(fin);
return 0;
}
I am a complete beginner in OS. The problem I am having is that I want to receive a value from a thread into the main process. A garbage value is printed in the main. Please elaborate so I can know my mistake.
Here is my code:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <iostream>
#include<string.h>
#include <sys/wait.h>
#include<pthread.h>
#include <sys/types.h>
#include<sys/stat.h>
#include<errno.h>
#include<fcntl.h>
#include<time.h>
#include <fstream>
#include<vector>
using namespace std;
void *thread_1(void *arg);
int main(int argc, char* argv[])
{
void *temp;
pthread_t t1;
pthread_create(&t1, NULL,thread_1,NULL);
pthread_join(t1,&temp);
int *num = (int*)temp;
cout<<"Value in main: "<<*num<<endl;
}
void *thread_1(void *arg)
{
int number = 5;
int* value = &number;
cout<<"Value in thread: "<<*value<<endl;
pthread_exit((void*)value);
}
You have two ways to do this:
Pass a pointer to an integer as the argument to the thread, and have the thread modify the argument to hold the value you want.
Have the thread allocate a value on the heap and return a pointer to that memory. Then clean it up later.
#include <iostream>
#include <pthread.h>
void *thread_1(void *arg);
void *thread_2(void *arg);
int main(int argc, char* argv[])
{
int value = 0;
pthread_t t1;
pthread_create(&t1, NULL,thread_1, &value);
pthread_join(t1, NULL);
std::cout<<"Value in main: "<<value<<std::endl;
int* value2 = NULL;
pthread_t t2;
pthread_create(&t2, NULL,thread_2, NULL);
pthread_join(t2, reinterpret_cast<void**>(&value2));
if (value2) {
std::cout<<"Value in main: "<<*value2<<std::endl;
delete value2;
}
}
void *thread_1(void *arg)
{
int* value = static_cast<int*>(arg);
*value = 5;
std::cout<<"Value in thread: "<<*value<<std::endl;
pthread_exit(NULL);
}
void *thread_2(void *arg)
{
int* value = new int(10);
std::cout<<"Value in thread: "<<*value<<std::endl;
pthread_exit(static_cast<void*>(value));
}
Try:
void *thread_1(void *arg)
{
int value = *((int *)arg);
cout<<"Value in thread: "<<value<<endl;
int new_val = 345;
pthread_exit(&new_val );
}
int main(int argc, char* argv[])
{
int *temp=15;
void *return_val;
pthread_t t1;
pthread_create(&t1, NULL,thread_1,(void *)temp);
pthread_join(t1,&return_val);
cout<<"Value in main: "<<*temp<<endl;
cout<<"Value from loop: "<<*(int*)return_val<<endl;
}
More info: http://www.cse.cuhk.edu.hk/~ericlo/teaching/os/lab/9-PThread/Pass.html
I've never worked with file descriptors and I'm a bit confused about some of this behavior. I'm also fairly new to concurrency and the documentation for these functions is fairly lacking.
My MessageReciever constructor opens a pty. Upon calling the Receive message, as I understand it, the code forks. The master should hit the next conditional and return from the function. I know this is happening because the code in main doesn't block. The child reads in the file descriptor, converts it to a string and saves it in a vector. Currently I'm printing the buffer directly but I also can print the last element in the vector and it acts basically the same. However, when I attempt to access this outside the class, in main, I get nothing. I thought this might be some type of concurrency problem, but I'm not really sure how to address.
CODE
#include <sys/time.h>
#include <sys/types.h>
#include <sys/select.h>
#include <stdio.h>
#include <util.h>
#include <unistd.h>
#include <sys/wait.h>
#include <string>
#include <vector>
class MessageReceiver
{
public:
MessageReceiver()
{
openpty(&master, &slave, NULL, NULL, NULL);
}
~MessageReceiver()
{
close(master);
close(slave);
}
void receiveMessage()
{
pid_t pid = fork();
printf("PID = %d\n",pid);
if(pid > 0)
{
fd_set rfds;
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 0;
char buf[4097];
ssize_t size;
size_t count = 0;
while (1)
{
if (waitpid(pid, NULL, WNOHANG) == pid)
{
break;
}
FD_ZERO(&rfds);
FD_SET(master, &rfds);
if (select(master + 1, &rfds, NULL, NULL, &tv))
{
size = read(master, buf, 4096);
printf("Buffer = %s", buf);
messageBuffer.push_back(std::string(buf));
buf[size] = '\0';
count += size;
}
}
}
}
std::string getLastMessage()
{
std::string s;
if(messageBuffer.size() > 0)
{
s = messageBuffer.back();
}
else
{
s = "NULL";
}
return s;
}
private:
int master, slave;
std::vector<std::string> messageBuffer;
};
int main()
{
MessageReceiver m;
m.receiveMessage();
std::string lastMessage = m.getLastMessage();
printf("Printing message buffer:\n");
for(;;)
{
if(m.getLastMessage() != lastMessage)
{
printf("Message: %s\n", m.getLastMessage().c_str());
}
}
return 0;
}
Initial output
PID = 8170
PID = 0
Printing message buffer:
Additional output when hello is echoed to the pty
Buffer = hello
Try to do something with shared memory by turning a chunk of user buffer into a shared memory, but the shmat() keep failing.
# ./a.out
shmid=89260087 0x7fbab055c000
shmat failed: : Invalid argument
Here is the source code. Wonder what's the reason. Thanks.
#include <arpa/inet.h>
#include <string.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <malloc.h>
char *output;
int n;
int main (int argc, char *argv[]) {
void *p = NULL;
int i;
double startTS;
double tmp;
output = (char*) valloc(0x1000000);
sprintf(output, "hi you!!");
unsigned int size = 0x1000000;
int shmid = shmget(12348, 0x1000000, IPC_CREAT); //SHM_RDONLY);
printf("shmid=%d %p\n", shmid, &output[0]);
char *bigBuf = (char*)shmat(shmid, &output[0], 0);
if (bigBuf == (void*)-1) {
perror("shmat failed: "); exit(-1);
}
bigBuf[0] = 'x';
printf("%p enter:\n", bigBuf);
scanf("%d\n", &i);
return 0;
}
I have a trouble with SIGALRM. I am using it to write pids of active processes every 3 seconds.
But after it fires once it kills main process. What did I do wrong?
I am also using signals to kill each of child processes after some time, I am using SIGTERM there.
It wors just fine until I add this part to list active processes. Even after killing main one the others are still going.
#include <iostream>
#include <string>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <time.h>
#include <signal.h>
#include <time.h>
#include <map>
using namespace std;
////DARK SORROW PLACE////////////////////////////
#define CHLD_DELAY 3
std::map<pid_t, bool> pidy;
/////////////////////////////////////////////////
void sweetDreams(int sec, int nanosec)
{
timespec ttw;
ttw.tv_sec = sec;
ttw.tv_nsec = nanosec;
while( nanosleep( &ttw, &ttw) && ( errno != EINTR ) ) continue;
}
//////////////////////////////////////////////////
void ns(long int ns, timespec *ts)
{
ts->tv_sec = (time_t)ns/1000000000;
ts->tv_nsec = (long)(ns - ts->tv_sec*1000000000);
}
//////////////////////////////////////////////////
class Order
{
public:
char* table;
int start;
int step;
int shift;
long int dt;
long int dieAfter;
};
////////////////////////////////////////////////////
void killer(int sig, siginfo_t *siginfo, void *context)
{
// kill(siginfo->si_pid, NULL);
_exit(0);
}
////////////////////////////////////////////////////
void carefullDad(int sig)
{
cout << "lista zywych dzieci:\n-----------------------" << endl;
for(auto i : pidy)
{
if( i.second ) cout << i.first << endl;
}
cout << "-----------------------" << endl;
}
////////////////////////////////////////////////////
int main(int argc, char** argv)
{
char test[] = { 't', 'e', 's', 't' };
Order orderArr[2] = {
{test, 0, 2, 0, 1000000000L, 10000000000L},
{test, 1, 3, -32 , 2000000000L, 6000000000L}
};
//pid_t pidArr[sizeof(orderArr) / sizeof(Order)];
pid_t wpid;
int status = 0;
struct sigevent st;
// memset(&st, 0, sizeof(st));
st.sigev_notify = SIGEV_SIGNAL;
st.sigev_signo = SIGALRM;
struct itimerspec it;
//memset(&it, 0, sizeof(it));
it.it_value = { CHLD_DELAY,0L};
it.it_interval = {CHLD_DELAY,0L};
struct sigaction act;
sigemptyset(&act.sa_mask);
act.sa_handler = carefullDad;
sigaction(SIGALRM, &act, NULL);
timer_t timer;
timer_create( CLOCK_REALTIME, &st, &timer);
timer_settime(timer, 0, &it, NULL);
for(Order ord : orderArr)
{
// static int i = 0;
pid_t pid = fork();
if(pid == -1)
{
cerr << "Blad!!!" << endl;
exit(1);
}
if(!pid)
{
//some code here
//end rest is here
You forgot to set act.sa_flags.
struct sigaction act;
sigemptyset(&act.sa_mask);
act.sa_handler = carefullDad;
act.sa_flags = 0;
sigaction(SIGALRM, &act, NULL);
When you set the signal handler it probably had the SA_RESETHAND flag set.
Either ignore the SIGALRM using sigprocmask() or install a valid handler using sigaction().
For everyone encountering this problem in the future.
You need to set:
struct sigaction act;
act.sa_handler = carefullDad;
act.sa_flags = SA_RESTART;
sigaction(SIGALRM, &act, NULL);