/* **************************************************************************** * Copyright IBM Corporation 1988, 1989 - All Rights Reserved * * * * Permission to use, copy, modify, and distribute this software and its * * documentation for any purpose and without fee is hereby granted, * * provided that the above copyright notice appear in all copies and * * that both that copyright notice and this permission notice appear in * * supporting documentation, and that the name of IBM not be used in * * advertising or publicity pertaining to distribution of the software * * without specific, written prior permission. * * * * IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL * * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL IBM * * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY * * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER * * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * **************************************************************************** */ /*******************************************************************\ * * * Information Technology Center * * Carnegie-Mellon University * * * * * \*******************************************************************/ #include #include #include #include /* allocate externs here */ #define LWP_KERNEL #include "lwp.h" RCSID("$Id: lwp_asm.c,v 1.1 2000/09/11 14:41:08 art Exp $"); #ifdef AFS_AIX32_ENV #include #include #include #include #include #pragma alloca #endif extern char PRE_Block; /* from preempt.c */ #define ON 1 #define OFF 0 #define TRUE 1 #define FALSE 0 #define READY 2 #define WAITING 3 #define DESTROYED 4 #define QWAITING 5 #define MAXINT (~(1<<((sizeof(int)*8)-1))) #define MINSTACK 44 /* * I don't really know if this is the right thing to do, but * now I don't get any unalinged memory access on my alpha /lha */ #if defined(__alpha) || defined(__uxpv__) || defined(__sparcv9) #define REGSIZE 8 #else #define REGSIZE 4 #endif #ifdef __hp9000s800 #define MINFRAME 64 #endif /* Debugging macro */ #ifdef DEBUG #define Debug(level, msg)\ if (lwp_debug && lwp_debug >= level) {\ printf("***LWP (%p): ", lwp_cpptr);\ printf msg;\ putchar('\n');\ } #else #define Debug(level, msg) #endif /* Prototypes */ static void Abort_LWP(char *msg) ; static void Dispatcher(void); static void Create_Process_Part2(void); static void purge_dead_pcbs(void) ; static void Overflow_Complain (void) ; static void Dispose_of_Dead_PCB (PROCESS cur) ; static void Free_PCB(PROCESS pid) ; static void Exit_LWP(void); static void Initialize_PCB(PROCESS temp, int priority, char *stack, int stacksize, void (*ep)() , char *parm, char *name) ; static long Initialize_Stack(char *stackptr,int stacksize) ; static int Stack_Used(char *stackptr, int stacksize) ; static int Internal_Signal(register char *event) ; char (*RC_to_ASCII()); #define MAX_PRIORITIES (LWP_MAX_PRIORITY+1) struct QUEUE { PROCESS head; int count; } runnable[MAX_PRIORITIES], blocked; /* * Invariant for runnable queues: The head of each queue points to the * currently running process if it is in that queue, or it points to the * next process in that queue that should run. */ /* Offset of stack field within pcb -- used by stack checking stuff */ int stack_offset; /* special user-tweakable option for AIX */ int lwp_MaxStackSize = 32768; /* biggest LWP stack created so far */ int lwp_MaxStackSeen = 0; /* Stack checking action */ int lwp_overflowAction = LWP_SOABORT; /* Controls stack size counting. */ int lwp_stackUseEnabled = TRUE; /* pay the price */ int lwp_nextindex; static void lwp_remove(register PROCESS p, register struct QUEUE *q) { /* Special test for only element on queue */ if (q->count == 1) q -> head = NULL; else { /* Not only element, do normal remove */ p -> next -> prev = p -> prev; p -> prev -> next = p -> next; } /* See if head pointing to this element */ if (q->head == p) q -> head = p -> next; q->count--; p -> next = p -> prev = NULL; } static void insert(register PROCESS p, register struct QUEUE *q) { if (q->head == NULL) { /* Queue is empty */ q -> head = p; p -> next = p -> prev = p; } else { /* Regular insert */ p -> prev = q -> head -> prev; q -> head -> prev -> next = p; q -> head -> prev = p; p -> next = q -> head; } q->count++; } static void move(PROCESS p, struct QUEUE *from, struct QUEUE *to) { lwp_remove(p, from); insert(p, to); } /* Iterator macro */ #define for_all_elts(var, q, body)\ {\ register PROCESS var, _NEXT_;\ register int _I_;\ for (_I_=q.count, var = q.head; _I_>0; _I_--, var=_NEXT_) {\ _NEXT_ = var -> next;\ body\ }\ } /* */ /*****************************************************************************\ * * * Following section documents the Assembler interfaces used by LWP code * * * \*****************************************************************************/ /* * savecontext(int (*ep)(), struct lwp_context *savearea, char *sp); * XXX - the above prototype is a lie. * Stub for Assembler routine that will * save the current SP value in the passed * context savearea and call the function * whose entry point is in ep. If the sp * parameter is NULL, the current stack is * used, otherwise sp becomes the new stack * pointer. * * returnto(struct lwp_context *savearea); * * Stub for Assembler routine that will * restore context from a passed savearea * and return to the restored C frame. * */ void savecontext(void (*)(), struct lwp_context *, char *); void returnto(struct lwp_context *); /* Macro to force a re-schedule. Strange name is historical */ #define Set_LWP_RC() savecontext(Dispatcher, &lwp_cpptr->context, NULL) static struct lwp_ctl *lwp_init = 0; int LWP_QWait(void) { register PROCESS tp; (tp=lwp_cpptr) -> status = QWAITING; lwp_remove(tp, &runnable[tp->priority]); Set_LWP_RC(); return LWP_SUCCESS; } int LWP_QSignal(register PROCESS pid) { if (pid->status == QWAITING) { pid->status = READY; insert(pid, &runnable[pid->priority]); return LWP_SUCCESS; } else return LWP_ENOWAIT; } #ifdef AFS_AIX32_ENV char * reserveFromStack(size) register long size; { char *x; x = alloca(size); return x; } #endif int LWP_CreateProcess(void (*ep)(), int stacksize, int priority, char *parm, char *name, PROCESS *pid) { PROCESS temp, temp2; #ifdef AFS_AIX32_ENV static char *stackptr = 0; #else char *stackptr; #endif #if defined(AFS_LWP_MINSTACKSIZE) /* * on some systems (e.g. hpux), a minimum usable stack size has * been discovered */ if (stacksize < AFS_LWP_MINSTACKSIZE) { stacksize = AFS_LWP_MINSTACKSIZE; } #endif /* defined(AFS_LWP_MINSTACKSIZE) */ /* more stack size computations; keep track of for IOMGR */ if (lwp_MaxStackSeen < stacksize) lwp_MaxStackSeen = stacksize; Debug(0, ("Entered LWP_CreateProcess")) /* Throw away all dead process control blocks */ purge_dead_pcbs(); if (lwp_init) { temp = (PROCESS) malloc (sizeof (struct lwp_pcb)); if (temp == NULL) { Set_LWP_RC(); return LWP_ENOMEM; } if (stacksize < MINSTACK) stacksize = 1000; else #ifdef __hp9000s800 stacksize = 8 * ((stacksize+7) / 8); #else stacksize = REGSIZE * ((stacksize+REGSIZE-1) / REGSIZE); #endif #ifdef AFS_AIX32_ENV if (!stackptr) { /* * The following signal action for AIX is necessary so that in case of a * crash (i.e. core is generated) we can include the user's data section * in the core dump. Unfortunately, by default, only a partial core is * generated which, in many cases, isn't too useful. * * We also do it here in case the main program forgets to do it. */ struct sigaction nsa; extern int geteuid(); sigemptyset(&nsa.sa_mask); nsa.sa_handler = SIG_DFL; nsa.sa_flags = SA_FULLDUMP; sigaction(SIGSEGV, &nsa, NULL); /* * First we need to increase the default resource limits, * if necessary, so that we can guarantee that we have the * resources to create the core file, but we can't always * do it as an ordinary user. */ if (!geteuid()) { setlim(RLIMIT_FSIZE, 0, 1048575); /* 1 Gig */ setlim(RLIMIT_STACK, 0, 65536); /* 65 Meg */ setlim(RLIMIT_CORE, 0, 131072); /* 131 Meg */ } /* * Now reserve in one scoop all the stack space that will be used * by the particular application's main (i.e. non-lwp) body. This * is plenty space for any of our applications. */ stackptr = reserveFromStack(lwp_MaxStackSize); } stackptr -= stacksize; #else if ((stackptr = (char *) malloc(stacksize)) == NULL) { Set_LWP_RC(); return LWP_ENOMEM; } #endif if (priority < 0 || priority >= MAX_PRIORITIES) { Set_LWP_RC(); return LWP_EBADPRI; } Initialize_Stack(stackptr, stacksize); Initialize_PCB(temp, priority, stackptr, stacksize, ep, parm, name); insert(temp, &runnable[priority]); temp2 = lwp_cpptr; if (PRE_Block != 0) Abort_LWP("PRE_Block not 0"); /* Gross hack: beware! */ PRE_Block = 1; lwp_cpptr = temp; #ifdef __hp9000s800 savecontext(Create_Process_Part2, &temp2->context, stackptr+MINFRAME); #else savecontext(Create_Process_Part2, &temp2->context, stackptr+stacksize-REGSIZE); #endif /* End of gross hack */ Set_LWP_RC(); *pid = temp; return 0; } else return LWP_EINIT; } /* returns pid of current process */ int LWP_CurrentProcess(PROCESS *pid) { Debug(0, ("Entered Current_Process")) if (lwp_init) { *pid = lwp_cpptr; return LWP_SUCCESS; } else return LWP_EINIT; } #define LWPANCHOR (*lwp_init) /* destroy a lightweight process */ int LWP_DestroyProcess(PROCESS pid) { PROCESS temp; Debug(0, ("Entered Destroy_Process")) if (lwp_init) { if (lwp_cpptr != pid) { Dispose_of_Dead_PCB(pid); Set_LWP_RC(); } else { pid -> status = DESTROYED; move(pid, &runnable[pid->priority], &blocked); temp = lwp_cpptr; #ifdef __hp9000s800 savecontext(Dispatcher, &(temp -> context), &(LWPANCHOR.dsptchstack[MINFRAME])); #else savecontext(Dispatcher, &(temp -> context), &(LWPANCHOR.dsptchstack[(sizeof LWPANCHOR.dsptchstack)-REGSIZE])); #endif } return LWP_SUCCESS; } else return LWP_EINIT; } /* explicit voluntary preemption */ int LWP_DispatchProcess(void) { Debug(2, ("Entered Dispatch_Process")) if (lwp_init) { Set_LWP_RC(); return LWP_SUCCESS; } else return LWP_EINIT; } #ifdef DEBUG static void Dump_One_Process(PROCESS pid); static void Dump_Processes(void) { if (lwp_init) { register int i; for (i=0; i priority; return 0; } else return LWP_EINIT; } int LWP_InitializeProcessSupport(int priority, PROCESS *pid) { PROCESS temp; struct lwp_pcb dummy; register int i; Debug(0, ("Entered LWP_InitializeProcessSupport")) if (lwp_init != NULL) return LWP_SUCCESS; /* Set up offset for stack checking -- do this as soon as possible */ stack_offset = (char *) &dummy.stack - (char *) &dummy; if (priority >= MAX_PRIORITIES) return LWP_EBADPRI; for (i=0; icontext, NULL); LWPANCHOR.outersp = temp -> context.topstack; Set_LWP_RC(); *pid = temp; return LWP_SUCCESS; } /* signal the occurence of an event */ int LWP_INTERNALSIGNAL(void *event, int yield) { Debug(2, ("Entered LWP_SignalProcess")) if (lwp_init) { int rc; rc = Internal_Signal(event); if (yield) Set_LWP_RC(); return rc; } else return LWP_EINIT; } /* terminate all LWP support */ int LWP_TerminateProcessSupport(void) { register int i; Debug(0, ("Entered Terminate_Process_Support")) if (lwp_init == NULL) return LWP_EINIT; if (lwp_cpptr != LWPANCHOR.outerpid) Abort_LWP("Terminate_Process_Support invoked from wrong process!"); for (i=0; iecount || wcount<0) { Set_LWP_RC(); return LWP_EBADCOUNT; } if (ecount > lwp_cpptr->eventlistsize) { lwp_cpptr->eventlist = (char **)realloc(lwp_cpptr->eventlist, ecount*sizeof(char *)); lwp_cpptr->eventlistsize = ecount; } for (i=0; i eventlist[i] = evlist[i]; if (wcount > 0) { lwp_cpptr -> status = WAITING; move(lwp_cpptr, &runnable[lwp_cpptr->priority], &blocked); } lwp_cpptr -> wakevent = 0; lwp_cpptr -> waitcnt = wcount; lwp_cpptr -> eventcnt = ecount; Set_LWP_RC(); return LWP_SUCCESS; } return LWP_EINIT; } /* wait on a single event */ int LWP_WaitProcess(void *event) { char *tempev[2]; Debug(2, ("Entered Wait_Process")) if (event == NULL) return LWP_EBADEVENT; tempev[0] = event; tempev[1] = NULL; return LWP_MwaitProcess(1, tempev); } int LWP_StackUsed(PROCESS pid, int *max, int *used) { *max = pid -> stacksize; *used = Stack_Used(pid->stack, *max); if (*used == 0) return LWP_NO_STACK; return LWP_SUCCESS; } /* * The following functions are strictly * INTERNAL to the LWP support package. */ static void Abort_LWP(char *msg) { struct lwp_context tempcontext; Debug(0, ("Entered Abort_LWP")) printf("***LWP: %s\n",msg); printf("***LWP: Abort --- dumping PCBs ...\n"); #ifdef DEBUG Dump_Processes(); #endif if (LWPANCHOR.outersp == NULL) Exit_LWP(); else savecontext(Exit_LWP, &tempcontext, LWPANCHOR.outersp); } /* creates a context for the new process */ static void Create_Process_Part2(void) { PROCESS temp; Debug(2, ("Entered Create_Process_Part2")) temp = lwp_cpptr; /* Get current process id */ savecontext(Dispatcher, &temp->context, NULL); (*temp->ep)(temp->parm); LWP_DestroyProcess(temp); } /* remove a PCB from the process list */ static void Delete_PCB(register PROCESS pid) { Debug(4, ("Entered Delete_PCB")) lwp_remove(pid, (pid->blockflag || pid->status==WAITING || pid->status==DESTROYED ? &blocked : &runnable[pid->priority])); LWPANCHOR.processcnt--; } #ifdef DEBUG static void Dump_One_Process(PROCESS pid) { int i; printf("***LWP: Process Control Block at %p\n", pid); printf("***LWP: Name: %s\n", pid->name); if (pid->ep != NULL) printf("***LWP: Initial entry point: %p\n", pid->ep); if (pid->blockflag) printf("BLOCKED and "); switch (pid->status) { case READY: printf("READY"); break; case WAITING: printf("WAITING"); break; case DESTROYED: printf("DESTROYED"); break; default: printf("unknown"); } putchar('\n'); printf("***LWP: Priority: %d \tInitial parameter: %p\n", pid->priority, pid->parm); if (pid->stacksize != 0) { printf("***LWP: Stacksize: %d \tStack base address: %p\n", pid->stacksize, pid->stack); printf("***LWP: HWM stack usage: "); printf("%d\n", Stack_Used(pid->stack,pid->stacksize)); free (pid->stack); } printf("***LWP: Current Stack Pointer: %p\n", pid->context.topstack); if (pid->eventcnt > 0) { printf("***LWP: Number of events outstanding: %d\n", pid->waitcnt); printf("***LWP: Event id list:"); for (i=0;ieventcnt;i++) printf(" %p", pid->eventlist[i]); putchar('\n'); } if (pid->wakevent>0) printf("***LWP: Number of last wakeup event: %d\n", pid->wakevent); } #endif static void purge_dead_pcbs(void) { for_all_elts(cur, blocked, { if (cur->status == DESTROYED) Dispose_of_Dead_PCB(cur); }) } int LWP_TraceProcesses = 0; /* Lightweight process dispatcher */ static void Dispatcher(void) { register int i; #ifdef DEBUG static int dispatch_count = 0; if (LWP_TraceProcesses > 0) { for (i=0; iname); }) puts("]"); } printf("[Blocked (%d):", blocked.count); for_all_elts(p, blocked, { printf(" \"%s\"", p->name); }) puts("]"); } #endif /* * Check for stack overflow if this lwp has a stack. Check for * the guard word at the front of the stack being damaged and * for the stack pointer being below the front of the stack. * WARNING! This code assumes that stacks grow downward. */ #ifdef __hp9000s800 /* Fix this (stackcheck at other end of stack???) */ if (lwp_cpptr != NULL && lwp_cpptr->stack != NULL && (lwp_cpptr->stackcheck != *(long *)((lwp_cpptr->stack) + lwp_cpptr->stacksize - 4) || lwp_cpptr->context.topstack > lwp_cpptr->stack + lwp_cpptr->stacksize - 4)) { #else if (lwp_cpptr != NULL && lwp_cpptr->stack != NULL && (lwp_cpptr->stackcheck != *(long *)(lwp_cpptr->stack) || lwp_cpptr->context.topstack < lwp_cpptr->stack)) { #endif printf("stackcheck = %lul: stack = %lul\n", lwp_cpptr->stackcheck, *(long *)lwp_cpptr->stack); printf("topstack = %lul\n", *(long *)lwp_cpptr->context.topstack); switch (lwp_overflowAction) { case LWP_SOQUIET: break; case LWP_SOABORT: Overflow_Complain(); abort (); case LWP_SOMESSAGE: default: Overflow_Complain(); lwp_overflowAction = LWP_SOQUIET; break; } } /* * Move head of current runnable queue forward if current LWP * is still in it. */ if (lwp_cpptr != NULL && lwp_cpptr == runnable[lwp_cpptr->priority].head) runnable[lwp_cpptr->priority].head = runnable[lwp_cpptr->priority].head->next; /* Find highest priority with runnable processes. */ for (i=MAX_PRIORITIES-1; i>=0; i--) if (runnable[i].head != NULL) break; if (i < 0) Abort_LWP("No READY processes"); #ifdef DEBUG if (LWP_TraceProcesses > 0) printf("Dispatch %d [PCB at %p] \"%s\"\n", ++dispatch_count, runnable[i].head, runnable[i].head->name); #endif if (PRE_Block != 1) Abort_LWP("PRE_Block not 1"); lwp_cpptr = runnable[i].head; returnto(&lwp_cpptr->context); } /* Complain of a stack overflow to stderr without using stdio. */ static void Overflow_Complain (void) { static char msg1[] = "LWP: stack overflow in process "; static char msg2[] = "!\n"; write (2, msg1, sizeof(msg1) - 1); write (2, lwp_cpptr->name, strlen(lwp_cpptr->name)); write (2, msg2, sizeof(msg2) - 1); } static void Dispose_of_Dead_PCB (PROCESS cur) { Debug(4, ("Entered Dispose_of_Dead_PCB")) Delete_PCB(cur); Free_PCB(cur); /* Internal_Signal(cur); */ } static void Exit_LWP(void) { abort(); } static void Free_PCB(PROCESS pid) { Debug(4, ("Entered Free_PCB")) if (pid -> stack != NULL) { Debug(0, ("HWM stack usage: %d, [PCB at %p]", Stack_Used(pid->stack,pid->stacksize), pid)) free(pid -> stack); } if (pid->eventlist != NULL) free(pid->eventlist); free(pid); } static void Initialize_PCB(PROCESS temp, int priority, char *stack, int stacksize, void (*ep)(), char *parm, char *name) { register int i = 0; Debug(4, ("Entered Initialize_PCB")) if (name != NULL) while (((temp -> name[i] = name[i]) != '\0') && (i < 31)) i++; temp -> name[31] = '\0'; temp -> status = READY; temp -> eventlist = (char **)malloc(EVINITSIZE*sizeof(char *)); temp -> eventlistsize = EVINITSIZE; temp -> eventcnt = 0; temp -> wakevent = 0; temp -> waitcnt = 0; temp -> blockflag = 0; temp -> iomgrRequest = 0; temp -> priority = priority; temp -> index = lwp_nextindex++; temp -> stack = stack; temp -> stacksize = stacksize; #ifdef __hp9000s800 if (temp -> stack != NULL) temp -> stackcheck = *(long *) ((temp -> stack) + stacksize - 4); #else if (temp -> stack != NULL) temp -> stackcheck = *(long *) (temp -> stack); #endif temp -> ep = ep; temp -> parm = parm; temp -> misc = NULL; /* currently unused */ temp -> next = NULL; temp -> prev = NULL; temp -> rused = 0; temp -> level = 1; /* non-preemptable */ } static int Internal_Signal(register char *event) { int rc = LWP_ENOWAIT; register int i; Debug(0, ("Entered Internal_Signal [event id %p]", event)) if (!lwp_init) return LWP_EINIT; if (event == NULL) return LWP_EBADEVENT; for_all_elts(temp, blocked, { if (temp->status == WAITING) for (i=0; i < temp->eventcnt; i++) { if (temp -> eventlist[i] == event) { temp -> eventlist[i] = NULL; rc = LWP_SUCCESS; Debug(0, ("Signal satisfied for PCB %p", temp)) if (--temp->waitcnt == 0) { temp -> status = READY; temp -> wakevent = i+1; move(temp, &blocked, &runnable[temp->priority]); break; } } } }) return rc; } /* This can be any unlikely pattern except 0x00010203 or the reverse. */ #define STACKMAGIC 0xBADBADBA static long Initialize_Stack(char *stackptr, int stacksize) { register int i; Debug(4, ("Entered Initialize_Stack")) if (lwp_stackUseEnabled) for (i=0; i= 0 ; i--) if ((unsigned char) stackptr[i] != (i & 0xff)) return (i); return 0; } #else if (*(long *) stackptr == STACKMAGIC) return 0; else { for (i = 0; i < stacksize; i++) if ((unsigned char) stackptr[i] != (i & 0xff)) return (stacksize - i); return 0; } #endif } /* * Finds a free rock and sets its value to Value. * Return codes: * LWP_SUCCESS Rock did not exist and a new one was used * LWP_EBADROCK Rock already exists. * LWP_ENOROCKS All rocks are in use. * From the above semantics, you can only set a rock value once. * This is specificallY to prevent multiple users of the LWP package from * accidentally using the same Tag value and clobbering others. You can always * use one level of indirection to obtain a rock whose contents can change. */ int LWP_NewRock(int Tag, char *Value) { register int i; register struct rock *ra; /* rock array */ ra = lwp_cpptr->rlist; for (i = 0; i < lwp_cpptr->rused; i++) if (ra[i].tag == Tag) return(LWP_EBADROCK); if (lwp_cpptr->rused < MAXROCKS) { ra[lwp_cpptr->rused].tag = Tag; ra[lwp_cpptr->rused].value = Value; lwp_cpptr->rused++; return(LWP_SUCCESS); } else return(LWP_ENOROCKS); } /* * Obtains the pointer Value associated with the rock Tag of this LWP. * Returns: * LWP_SUCCESS if specified rock exists and Value has been filled * LWP_EBADROCK rock specified does not exist */ int LWP_GetRock(int Tag, char **Value) { register int i; register struct rock *ra; ra = lwp_cpptr->rlist; for (i = 0; i < lwp_cpptr->rused; i++) if (ra[i].tag == Tag) { *Value = ra[i].value; return(LWP_SUCCESS); } return(LWP_EBADROCK); } #ifdef AFS_AIX32_ENV setlim(limcon, hard, limit) int limcon; uchar_t hard; { struct rlimit rlim; (void) getrlimit(limcon, &rlim); limit = limit * 1024; if (hard) rlim.rlim_max = limit; else if (limit == RLIM_INFINITY && geteuid() != 0) rlim.rlim_cur = rlim.rlim_max; else rlim.rlim_cur = limit; /* Must use ulimit() due to Posix constraints */ if (limcon == RLIMIT_FSIZE) { if (ulimit(UL_SETFSIZE, ((hard ? rlim.rlim_max : rlim.rlim_cur) / 512)) < 0) { printf("Can't %s%s limit\n", limit == RLIM_INFINITY ? "remove" : "set", hard ? " hard" : ""); return (-1); } } else { if (setrlimit(limcon, &rlim) < 0) { perror(""); printf("Can't %s%s limit\n", limit == RLIM_INFINITY ? "remove" : "set", hard ? " hard" : ""); return (-1); } } return (0); } #ifdef notdef /* * Print the specific limit out */ plim(name, lc, hard) char *name; long lc; uchar_t hard; { struct rlimit rlim; int lim; printf("%s \t", name); (void) getrlimit(lc, &rlim); lim = hard ? rlim.rlim_max : rlim.rlim_cur; if (lim == RLIM_INFINITY) printf("unlimited"); printf("%d %s", lim / 1024, "kbytes"); printf("\n"); } #endif #endif