/* Copyright (C) 1992, the Florida State University
   Distributed by the Florida State University under the terms of the
   GNU Library General Public License.

This file is part of Pthreads.

Pthreads is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation (version 2).

Pthreads is distributed "AS IS" in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU Library General Public License for more details.

You should have received a copy of the GNU Library General Public
License along with Pthreads; see the file COPYING.  If not, write
to the Free Software Foundation, 675 Mass Ave, Cambridge,
MA 02139, USA.

Report problems and direct all questions to:

  pthreads-bugs@ada.cs.fsu.edu

  @(#)stack.c	1.16 3/5/93

*/

/*
 * Thread stack allocation.
 * This handles all stack allocation including defined policies.
 */

#include "pthread_internals.h"
#include <sun4/asm_linkage.h>
#include <sys/resource.h>
#include <sys/mman.h>

#ifdef STACK_CHECK
int page_size;
/*
 * page alignment
 */
#define PA(X) ((((int)X)+((int)page_size-1)) & ~((int)page_size-1))
#endif

/*------------------------------------------------------------*/
/*
 * stack_init - initialize the main thread's stack
 */
void stack_init(p)
pthread_t p;
{
  struct rlimit rlim;
  extern char *get_sp();
  
#ifdef STACK_CHECK
  page_size = getpagesize();
#endif

  /*
   * Stack size of the main thread is the stack size of the process
   */
  if (getrlimit(RLIMIT_STACK, &rlim) != 0) {
    perror("getrlimit");
    process_exit(1);
  }
  p->attr.stacksize = rlim.rlim_cur;

  /*
   * dummy stack base which can be freed
   */
  p->stack_base = malloc(sizeof(int));
  process_stack_base = get_sp();
}

/*------------------------------------------------------------*/
/*
 * alloc_stack - allocate stack space on heap for a thread
 * Stacks are deallocated when the thread has returned and is detached.
 */
int alloc_stack(p)
pthread_t p;
{
#ifndef _POSIX_THREAD_ATTR_STACKSIZE
  p->attr.stacksize = DEFAULT_STACKSIZE;
#endif
#ifdef STACK_CHECK
  p->stack_base = malloc(p->attr.stacksize + PTHREAD_BODY_OFFSET
			 + page_size * 2);
#else
  p->stack_base = malloc(p->attr.stacksize + PTHREAD_BODY_OFFSET);
#endif
  
  if ((int) p->stack_base == NULL) {
#ifdef DEBUG
    fprintf(stderr, "\n*** Out of space for thread stacks. ***\n");
    fflush(stderr);
#endif
    return(FALSE);
  }
  
#ifdef STACK_CHECK
  /*
   * lock page at lower bound of stack to cause segmentation violation
   * when stack overflows
   */
  if (mprotect(PA(p->stack_base), page_size, PROT_NONE))
    return(FALSE);
#endif

  return(TRUE);
}
/*------------------------------------------------------------*/
#ifdef STACK_CHECK
/*
 * unlock_stack - unlock memory page on stack
 */
void unlock_stack(p)
pthread_t p;
{
  munmap(PA(p->stack_base), page_size);
}
#endif
