#include <qdos.h>

extern int _DEF_PRIORITY;
extern char _PROG_NAME[];
/* Number of currently running threads */
int _num_threads = 0;
extern void _thrd_term();

/********************************************************
 * Routine to return the number of active threads.		*
 ********************************************************/

int num_thrd()
{
	return _num_threads ;
}

/********************************************************
 * Routine to start a subroutine up as a separate job	*
 ********************************************************/

long thread( rtn, name, priority, stacklen, arglen, arg1)
int (*rtn)(); /* Routine to activate as thread */
char *name; /* Name to give thread */
int priority; /* Priority to start thread at */
int stacklen; /* Length of stack to give thread */
register int arglen; /* Number of sizeof(int) 's of arguement list */
int arg1; /* Start of arguements for thread */
{
    char *jbadd;
	char full_name[80];
	register char *job_add; /* Address of job created */
    short *name_ptr; /* Pointer to use to give thread a name */
    register struct JOBHEADER *job_hdr; /* Address of job header */
    long job_id;

	if( stacklen == 0)
		stacklen = 2048; /* Default 2K stack */

	if( priority == 0)
		priority = _DEF_PRIORITY;

    if( name == NULL ) /* Ensure the thread has a name */
        name = "Thread";

	strcpy( full_name, _PROG_NAME); /* Job who owns this thread */
	strcat( full_name, "_");
	strcat( full_name, name);
	full_name[job_id=strlen(full_name)] = 'A' + _num_threads;
	full_name[job_id+1] = '\0';

    arglen <<= 2; /* Get correct arguement size */
    job_id = mt_cjob( 0L, (((stacklen + arglen + 8 + strlen(name) + 1)+1)&~1),
                      (char *)rtn, -1, &jbadd);

    if( _oserr )
        return 0; /* We know zero is not a valid new job */

	job_add = jbadd;
    /* Set up the thread's name and id */
    name_ptr = (short *)(job_add + 6); /* Position of name */
    *name_ptr++ = 0x4AFB; /* ID word for job */
    cstr_to_ql( (struct QLSTR *)name_ptr, full_name);

    job_hdr = (struct JOBHEADER *)(job_add - sizeof( struct JOBHEADER));
    /* Set up registers for thread */
    job_hdr->jb_regs.jb_A7 -= arglen;
    /* Put the parameters on the new thread's stack */
    memcpy( job_hdr->jb_regs.jb_A7, &arg1, arglen);
    /* Now set the return address */
    job_hdr->jb_regs.jb_A7 -= 4;
    *(void (**) ())job_hdr->jb_regs.jb_A7 = _thrd_term; /* Exit routine */
    /* Start the thread with the required priority */
    mt_activ( job_id, priority, 0);
	_num_threads++;
    return job_id;
}
