Skip to content
  • Nathan Froyd's avatar
    linux-user: fix memory leaks with NPTL emulation · 48e15fc2
    Nathan Froyd authored
    
    
    Running programs that create large numbers of threads, such as this
    snippet from libstdc++'s pthread7-rope.cc:
    
      const int max_thread_count = 4;
      const int max_loop_count = 10000;
      ...
      for (int j = 0; j < max_loop_count; j++)
        {
          ...
          for (int i = 0; i < max_thread_count; i++)
    	pthread_create (&tid[i], NULL, thread_main, 0);
    
          for (int i = 0; i < max_thread_count; i++)
    	pthread_join (tid[i], NULL);
        }
    
    in user-mode emulation will quickly run out of memory.  This is caused
    by a failure to free memory in do_syscall prior to thread exit:
    
              /* TODO: Free CPU state.  */
              pthread_exit(NULL);
    
    The first step in fixing this is to make all TaskStates used by QEMU
    dynamically allocated.  The TaskState used by the initial thread was
    not, as it was allocated on main's stack.  So fix that, free the
    cpu_env, free the TaskState, and we're home free, right?
    
    Not exactly.  When we create a thread, we do:
    
            ts = qemu_mallocz(sizeof(TaskState) + NEW_STACK_SIZE);
            ...
            new_stack = ts->stack;
            ...
            ret = pthread_attr_setstack(&attr, new_stack, NEW_STACK_SIZE);
    
    If we blindly free the TaskState, then, we yank the current (host)
    thread's stack out from underneath it while it still has things to do,
    like calling pthread_exit.  That causes problems, as you might expect.
    
    The solution adopted here is to let the C library allocate the thread's
    stack (so the C library can properly clean it up at pthread_exit) and
    provide a hint that we want NEW_STACK_SIZE bytes of stack.
    
    With those two changes, we're done, right?  Well, almost.  You see,
    we're creating all these host threads and their parent threads never
    bother to check that their children are finished.  There's no good place
    for the parent threads to do so.  Therefore, we need to create the
    threads in a detached state so the parent thread doesn't have to call
    pthread_join on the child to release the child's resources; the child
    does so automatically.
    
    With those three major changes, we can comfortably run programs like the
    above without exhausting memory.  We do need to delete 'stack' from the
    TaskState structure.
    
    Signed-off-by: default avatarNathan Froyd <froydnj@codesourcery.com>
    Signed-off-by: default avatarRiku Voipio <riku.voipio@nokia.com>
    48e15fc2