1

I'm working on a multi-threading project and I need to make a copy of a thread's stack at some point in code (I need a pointer to that). because I'm going to need that pointer after this thread is exited (and it's stack is freed). It would also do the job if I could somehow tell pthread_exit() not to free the stack of thread!

PS: The reason behind this is that I want to use setcontext(ucontext_t*) later when this thread is actually dead.

Pawan
  • 1,537
  • 1
  • 15
  • 19
zmeftah
  • 148
  • 1
  • 2
  • 10
  • 2
    I think you suffer from the XY problem. What is the thing you try to achieve with that? – fuz Jul 31 '15 at 14:26
  • @FUZxxl: I want to hide a waiting thread so the OS wouldn't see it, (it's for some scheduling test). I thought I would kill it and then when I want to wake it up, I restore it. It's very necessary for my project to hide the thread. – zmeftah Jul 31 '15 at 14:37
  • 3
    If this is really necessary for your project then the solution to this is to write your own operating system, or at least threading library. – Art Jul 31 '15 at 14:38
  • @zmeftah And fine-tuning the scheduling with the functionality in `sched.h` isn't enough? – fuz Jul 31 '15 at 14:39
  • 2
    Notice that a thread comprises more than just the stack—there is thread-local storage and various other attributes. You can't preserve a thread just by preserving its stack. – fuz Jul 31 '15 at 14:40
  • by fine-tuning, do you mean SCHED_RR, SCHED_OTHER, ...? I don't think so, because I need to prevent OS from scheduling my thread for some time. I think I'm going to go through a lot of pain! – zmeftah Jul 31 '15 at 14:48
  • It's not even enough to copy the stack, because your process may have pointers to objects on the stack, so you'll need to make sure the copy gets mapped to the same addresses again. – EOF Jul 31 '15 at 15:11
  • @EOF oh! that's right, maybe I should look for another solution, now I'm going to decrease priority of a thread instead of killing it, and I hope it prevents OS from scheduling it. thank you very much. – zmeftah Jul 31 '15 at 15:20
  • ^^ good luck with that one:( The only chance you might get is to ensure that you have [cores] higher-priority threads ready, so that your target thread is run. Even then, you should be quick about it, since some OS anti-starvation mechanism may let it have a few cycles occasionally. – Martin James Jul 31 '15 at 15:23
  • ..unless it's already not ready, stuck in some blocking syscall. – Martin James Jul 31 '15 at 15:25
  • Anyway, you can forget about 'restoring' a thread state if it's actually got as far as being terminated. It's register set has gone, plus other reasons as commented by others. – Martin James Jul 31 '15 at 15:29
  • 2
    Why not have threads lock a `pthread_mutex_t`? – Jason Jul 31 '15 at 15:30
  • @zmeftah You could stop the thread with a `SIGSTOP`. – fuz Jul 31 '15 at 15:47
  • @FUZxxl Signals are scoped to the process, they can't be scoped to threads. If they could be thread scoped, you would also still have a race condition. Locking a `pthread_mutext_t` is the reliable method to do this. – Jason Jul 31 '15 at 15:59
  • @Jason What race-condition would you have? I don't see any that can't be avoided by careful programming. – fuz Jul 31 '15 at 16:00
  • @FUZxxl `SIGSTOP` can't be ignored, but the signal handler is process scoped which means it would stop *all* threads. Although, even if signal handlers were scoped to threads, there would still be a race condition between starting the thread and raising the `SIGSTOP` signal. – Jason Jul 31 '15 at 16:03
  • @Jason I think OPs intent is to stop the thread at a rough point in (wall clock) time, so the latter race condition doesn't matter. – fuz Jul 31 '15 at 16:07
  • @FUZxxl I added an answer with code for both below. – Jason Jul 31 '15 at 16:39
  • @zmeftah: The DIY solution without existing locking primitives would be: Select on a self pipe. As long as the pipe is dry (not bytes withing) the select will block indefinitely and the OS will not schedule the thread waiting on the select. Instead of a select a poll, epoll or similar will work, too. But I don't see, why a Mutex won't work for you either. – datenwolf Jul 31 '15 at 18:40
  • @datenwolf mutex does not work for me but I did not know that select prevents OS from scheduling a thread either, I'm going to google about it. thank you. – zmeftah Jul 31 '15 at 18:59

2 Answers2

5

As was mentioned, this may be a case of the XY problem. However, the solution is to use a pthread_mutex_t in each thread.

The function creating the thread would create the pthread_mutext_t and pass it to the thread.

pthread_t tid;
pthread_mutext_t mutex;

pthread_mutex_init(&mutex, NULL);
pthread_mutex_lock(&mutex);

pthread_create(&tid, NULL, fun, &mutex);

// do stuff

pthread_mutex_unlock(&mutex);

The thread function would be as follows...

void fun(void* arg) {

  pthread_mutex_t* mutex = (pthread_mutex_t*) arg;
  pthread_mutex_lock(mutex);

  // do stuff
}

If you need to do this asynchronously, you can register a signal handler for SIGUSR1 and SIGUSR2 and use pause to unschedule the thread.

signal(SIGUSR1, on_usr1);
signal(SIGUSR2, on_usr2);

void on_usr1(int sig) {

  pause();
}

void on_usr2(int sig) {
}

Then use pthread_kill to raise the signal to the thread...

pthread_kill(tid, SIGUSR1);
Jason
  • 3,777
  • 14
  • 27
  • pthread_lock cannot solve my problem because I need to make sure that OS did not schedule my thread. but I did not know about pause. thank you for that. – zmeftah Jul 31 '15 at 18:51
  • @zmeftah Why do you need to make sure the OS doesn't schedule the thread at all? – Jason Jul 31 '15 at 19:02
  • because then I'm going to use a benchmark program and get some results and do some comparison... stuff like that. the situation I'm testing is that OS should not schedule it at all. – zmeftah Jul 31 '15 at 19:08
  • @zmeftah I think this may be another example of XY. What are the benchmarks? What are the magnitudes you are using for your benchmarks? – Jason Jul 31 '15 at 19:18
  • it's [parsec](http://parsec.cs.princeton.edu/) benchmark from princeton, my job is not to let OS schedule a thread, in anyway that I can. first I was trying to implement my own ULT library but multiprocessing had a lot of cost that it actually was not useful. then I decided to use pthreads and somehow prevent OS from scheduling it. – zmeftah Jul 31 '15 at 19:30
  • @zmeftah You can't create a thread in any other state than running. The only hope you might have is somehow spawning a thread in a null cpuset or actually modifying the kernel. What's the impact of the time between a thread starting and locking? That timespan is likely ~100ns. – Jason Jul 31 '15 at 20:06
  • I cannot modify kernel, but null cpuset sounds very good, I would google it and I really hope it's a practical thing. (I did not know we could have control over the cpuset a thread is running on :)) – zmeftah Jul 31 '15 at 20:20
  • @zmeftah You still haven't explained the need for the requirement. I'm confident the real solution to your problem is going to be using `pthread_mutext_t`. – Jason Jul 31 '15 at 20:35
1

As the commenters have said, saving a thread stack to restore it later is going to be really hard. If what you need is to prevent the thread to be called, you can try and "pause" it with a lock. See an example here.

Community
  • 1
  • 1
ChatterOne
  • 3,381
  • 1
  • 18
  • 24
  • unfortunately, a lock is exactly what I don't want (I don't trust it) because with locks, there is no way to make sure that OS did not schedule my thread, and I need to prove something. – zmeftah Jul 31 '15 at 18:48
  • 1
    Well, I'm fairly sure that, with functional operating systems, a thread stuck on, say, a semaphore, will not be given any CPU cycles at all. – Martin James Aug 01 '15 at 04:44