コード例 #1
0
ファイル: ThreadPool.c プロジェクト: philippe44/pupnp
int ThreadPoolAdd(ThreadPool *tp, ThreadPoolJob *job, int *jobId)
{
	int rc = EOUTOFMEM;
	int tempId = -1;
	long totalJobs;
	ThreadPoolJob *temp = NULL;

	if (!tp || !job)
		return EINVAL;

	ithread_mutex_lock(&tp->mutex);

	totalJobs = tp->highJobQ.size + tp->lowJobQ.size + tp->medJobQ.size;
	if (totalJobs >= tp->attr.maxJobsTotal) {
		fprintf(stderr, "total jobs = %ld, too many jobs", totalJobs);
		goto exit_function;
	}
	if (!jobId)
		jobId = &tempId;
	*jobId = INVALID_JOB_ID;
	temp = CreateThreadPoolJob(job, tp->lastJobId, tp);
	if (!temp)
		goto exit_function;
	switch (job->priority) {
	case HIGH_PRIORITY:
		if (ListAddTail(&tp->highJobQ, temp))
			rc = 0;
		break;
	case MED_PRIORITY:
		if (ListAddTail(&tp->medJobQ, temp))
			rc = 0;
		break;
	default:
		if (ListAddTail(&tp->lowJobQ, temp))
			rc = 0;
	}
	/* AddWorker if appropriate */
	AddWorker(tp);
	/* Notify a waiting thread */
	if (rc == 0)
		ithread_cond_signal(&tp->condition);
	else
		FreeThreadPoolJob(tp, temp);
	*jobId = tp->lastJobId++;

exit_function:
	ithread_mutex_unlock(&tp->mutex);

	return rc;
}
コード例 #2
0
BOOL ReadMacro(HPTR hpBuf, LPLIST lpMacroList, BOOL fReadFirstPacketOnly)
/***********************************************************************/
{
LPTSTR lpCommand;
MACRO_FILE_HANDLE fh;
LPCMDPKT lpCmdPkt;
BOOL fError;

// zero out the list
ListInit(lpMacroList);

// Allocate a buffer to read the commands into
if (!(lpCommand = (LPTSTR)Alloc(MAX_CMD_LEN)))
	{
	Message(IDS_EMEMALLOC);
	return(FALSE);
	}
while (lpCmdPkt = ReadPacket(&hpBuf, lpCommand, &fError))
	{
	ListAddTail(lpMacroList, lpCmdPkt);
	if (fReadFirstPacketOnly)
		break;
	}
FreeUp(lpCommand);
if (fError)
	{
	DestroyPacketList(lpMacroList);
	return(FALSE);
	}
return(TRUE);
}
コード例 #3
0
ファイル: alloc.c プロジェクト: caryhaynie/gcom
static
void *IMalloc_Alloc( IMalloc *self, uint32 cBytes )
{
   AllocNode *an;

   /* IMalloc requires us to implement the DidAlloc() function,
    * which returns non-zero if we allocated a particular chunk
    * of memory.
    * 
    * In order to properly implement that functionality, this
    * code allocates the requested memory, and adds that memory
    * to a doubly-linked list, maintained internally as part of
    * the object's state.  This way, we have a record of which
    * chunks of memory we did and did not allocate.
    */

   an = (AllocNode *)malloc( cBytes + sizeof( AllocNode ) );
   if( an != NULL )
   {
      /* Fill in some bookkeeping information. */

      an -> size = cBytes;	/* For the IMalloc::GetSize() function */
      LockAllocList();
      ListAddTail( &allocList, (Node *)an );
      UnlockAllocList();
      
      /* Now advance "an" to point to the memory requested by the client */
      an++;
   }

   return (void *)an;
}
コード例 #4
0
BOOL ReadMacro(LPTSTR lpFileName, LPLIST lpMacroList, BOOL fReadFirstPacketOnly)
/***********************************************************************/
{
LPTSTR lpCommand;
MACRO_FILE_HANDLE fh;
LPCMDPKT lpCmdPkt;
BOOL fError;
FNAME OEMName;

// zero out the list
ListInit(lpMacroList);

// Open the macro file
#ifdef BUFFERED_IO
AnsiToOem(lpFileName, OEMName);
fh = fopen(OEMName, _T("rb"));
if (fh == NULL)
#else
fh = FileOpen(lpFileName, FO_READ);
if (fh == MACRO_FILE_HANDLE_INVALID)
#endif
	{
	Message(IDS_EOPEN, lpFileName);
	return(FALSE);
	}
// Allocate a buffer to read the commands into
if (!(lpCommand = (LPTSTR)Alloc(MAX_CMD_LEN)))
	{
#ifdef BUFFERED_IO
	fclose(fh);
#else
	FileClose(fh);
#endif
	Message(IDS_EMEMALLOC);
	return(FALSE);
	}
AstralCursor(IDC_WAIT);
while (lpCmdPkt = ReadPacket(fh, lpCommand, &fError))
	{
	ListAddTail(lpMacroList, lpCmdPkt);
	if (fReadFirstPacketOnly)
		break;
	}
AstralCursor(NULL);
FreeUp(lpCommand);
#ifdef BUFFERED_IO
fclose(fh);
#else
FileClose(fh);
#endif
if (fError)
	{
	DestroyPacketList(lpMacroList);
	return(FALSE);
	}
return(TRUE);
}
コード例 #5
0
void CgiListMake(const Cgi cgi)
{
  struct pair *psp;
  
  assert(cgi != NULL);
  
  while((psp = CgiNextValue(cgi)) != NULL)
    ListAddTail(&cgi->vars,&psp->node);
}
コード例 #6
0
ファイル: gamelist.c プロジェクト: arunpersaud/xboard
/* Creates a new game for the gamelist.
 */
static int
GameListNewGame (ListGame **listGamePtr)
{
    if (!(*listGamePtr = (ListGame *) GameListCreate())) {
	GameListFree(&gameList);
	return(ENOMEM);
    }
    ListAddTail(&gameList, (ListNode *) *listGamePtr);
    return(0);
}
コード例 #7
0
ファイル: alloc.c プロジェクト: caryhaynie/gcom
static
void *IMalloc_Realloc( IMalloc *self, void *pv, uint32 cBytes )
{
   AllocNode *an1 = ( (AllocNode *)pv ) - 1;
   AllocNode *an2;

   /*
    * Unlike the other memory allocation functions, we must lock the
    * list for the entire duration of the realloc operation.  This is
    * because we must, essentially, perform a "read-modify-write"
    * operation on the list, and it must be atomic.
    * 
    * The reason is realloc() *could* relocate a chunk of data, rather
    * than extending a chunk in-place.  As a result, we must remove the
    * allocated node from the list, realloc() it, and then place it back
    * onto the list.
    */

   LockAllocList();

   NodeRemove( (Node *)an1 );
   an2 = (AllocNode *)realloc( an1, cBytes + sizeof( AllocNode ) );
   
   if( an2 != NULL )
   {
      an2 -> size = cBytes;
      ListAddTail( &allocList, (Node *)an2 );
      UnlockAllocList();
      
      return (void *)( an2 + 1 );
   }
   else
   {
      ListAddTail( &allocList, (Node *)an1 );
      UnlockAllocList();

      return NULL;
   }
}
コード例 #8
0
/****************************************************************************
 * Function: BumpPriority
 *
 *  Description:
 *      Determines whether any jobs
 *      need to be bumped to a higher priority Q and bumps them.
 *
 *      tp->mutex must be locked.
 *      Internal Only.
 *  Parameters:
 *      ThreadPool *tp
 *****************************************************************************/
static void BumpPriority( ThreadPool *tp )
{
    int done = 0;
    struct timeval now;
    unsigned long diffTime = 0;
    ThreadPoolJob *tempJob = NULL;

    assert( tp != NULL );

    gettimeofday(&now, NULL);	

    while( !done ) {
        if( tp->medJobQ.size ) {
            tempJob = ( ThreadPoolJob *) tp->medJobQ.head.next->item;
            diffTime = DiffMillis( &now, &tempJob->requestTime );
            if( diffTime >= ( tp->attr.starvationTime ) ) {
                // If job has waited longer than the starvation time
                // bump priority (add to higher priority Q)
                StatsAccountMQ( tp, diffTime );
                ListDelNode( &tp->medJobQ, tp->medJobQ.head.next, 0 );
                ListAddTail( &tp->highJobQ, tempJob );
                continue;
            }
        }
        if( tp->lowJobQ.size ) {
            tempJob = ( ThreadPoolJob *) tp->lowJobQ.head.next->item;
            diffTime = DiffMillis( &now, &tempJob->requestTime );
            if( diffTime >= ( tp->attr.maxIdleTime ) ) {
                // If job has waited longer than the starvation time
                // bump priority (add to higher priority Q)
                StatsAccountLQ( tp, diffTime );
                ListDelNode( &tp->lowJobQ, tp->lowJobQ.head.next, 0 );
                ListAddTail( &tp->medJobQ, tempJob );
                continue;
            }
        }
        done = 1;
    }
}
コード例 #9
0
ファイル: dmscp.c プロジェクト: cvsuser-chromium/librhino
static void s_Dmscp_Register_ServiceCalback(t_DMC_SERVICE_UPDATED_CALLBACK callback, int hnd)
{
	int *p = (int*)malloc( sizeof(int) *2 );
	
	HT_DBG_FUNC_START(HT_MOD_DMC, HT_BIT_MANY,(int)callback, NULL);
	sem_wait(&(s_dmscp_service_updated_lock));

	p[0] = (int)callback;
	p[1] = hnd;
	ListAddTail( &s_dmscp_service_updated_list, p );

	sem_post(&(s_dmscp_service_updated_lock));
	HT_DBG_FUNC_END(hnd, NULL);
}
コード例 #10
0
/*-------------------------------------------------*/
static void s_Add_Object(char *buf, int IsPlayback)
{
	HT_DBG_FUNC_START(HT_MOD_IPC, HT_BIT_MANY, 0, buf);
	
	t_FAKE_OBJ *p = (t_FAKE_OBJ*)malloc(sizeof(t_FAKE_OBJ));
//	HT_DBG_FUNC(p, "p = ");
	p->IsPlayback	= IsPlayback;
//	HT_DBG_FUNC(p, "p = ");
	p->handle		= atoi(buf);
//	HT_DBG_FUNC(p, "p = ");
	ListAddTail(&s_object_list, p);
//	HT_DBG_FUNC(p, "p = ");
	
	sprintf(buf, "%d", (int)p);
	
	HT_DBG_FUNC_END((int)p, "fake = ");
}
コード例 #11
0
void RFC822HeadersRead(FILE *in,const List *list)
{
  char        *line;
  char        *t;
  struct pair *ppair;
  
  assert(in   != NULL);
  assert(list != NULL);
  
  while((line = RFC822LineRead(in)) != NULL)
  {
    t            = line;
    ppair        = PairNew(&t,':','\0');
    ppair->name  = trim_space(ppair->name);
    ppair->value = trim_space(ppair->value);
    up_string(ppair->name);
    ListAddTail((List *)list,&ppair->node);
    free(line);
  }  
}
コード例 #12
0
ファイル: tee_scheduler.c プロジェクト: HappyASR/Trust-E-OS
// 说明:加入就绪列表
void TaskAddReady(TASK *task)
{
    ListAddTail(&list_ready_tasks, &task->list_ready);
}
コード例 #13
0
ファイル: ssdp_ctrlpt.c プロジェクト: Tieske/pupnp
int SearchByTarget(int Mx, char *St, void *Cookie)
{
	char errorBuffer[ERROR_BUFFER_LEN];
	int *id = NULL;
	int ret = 0;
	char ReqBufv4[BUFSIZE];
#ifdef UPNP_ENABLE_IPV6
	char ReqBufv6[BUFSIZE];
	char ReqBufv6UlaGua[BUFSIZE];
#endif
	struct sockaddr_storage __ss_v4;
#ifdef UPNP_ENABLE_IPV6
	struct sockaddr_storage __ss_v6;
#endif
	struct sockaddr_in *destAddr4 = (struct sockaddr_in *)&__ss_v4;
#ifdef UPNP_ENABLE_IPV6
	struct sockaddr_in6 *destAddr6 = (struct sockaddr_in6 *)&__ss_v6;
#endif
	fd_set wrSet;
	SsdpSearchArg *newArg = NULL;
	int timeTillRead = 0;
	int handle;
	struct Handle_Info *ctrlpt_info = NULL;
	enum SsdpSearchType requestType;
	unsigned long addrv4 = inet_addr(gIF_IPV4);
	SOCKET max_fd = 0;
	int retVal;

	/*ThreadData *ThData; */
	ThreadPoolJob job;

	memset(&job, 0, sizeof(job));

	requestType = ssdp_request_type1(St);
	if (requestType == SSDP_SERROR)
		return UPNP_E_INVALID_PARAM;
	UpnpPrintf(UPNP_INFO, SSDP, __FILE__, __LINE__,
		   "Inside SearchByTarget\n");
	timeTillRead = Mx;
	if (timeTillRead < MIN_SEARCH_TIME)
		timeTillRead = MIN_SEARCH_TIME;
	else if (timeTillRead > MAX_SEARCH_TIME)
		timeTillRead = MAX_SEARCH_TIME;
	retVal = CreateClientRequestPacket(ReqBufv4, sizeof(ReqBufv4), timeTillRead, St, AF_INET);
	if (retVal != UPNP_E_SUCCESS)
		return retVal;
#ifdef UPNP_ENABLE_IPV6
	retVal = CreateClientRequestPacket(ReqBufv6, sizeof(ReqBufv6), timeTillRead, St, AF_INET6);
	if (retVal != UPNP_E_SUCCESS)
		return retVal;
	retVal = CreateClientRequestPacketUlaGua(ReqBufv6UlaGua, sizeof(ReqBufv6UlaGua), timeTillRead, St, AF_INET6);
	if (retVal != UPNP_E_SUCCESS)
		return retVal;
#endif

	memset(&__ss_v4, 0, sizeof(__ss_v4));
	destAddr4->sin_family = (sa_family_t)AF_INET;
	inet_pton(AF_INET, SSDP_IP, &destAddr4->sin_addr);
	destAddr4->sin_port = htons(SSDP_PORT);

#ifdef UPNP_ENABLE_IPV6
	memset(&__ss_v6, 0, sizeof(__ss_v6));
	destAddr6->sin6_family = (sa_family_t)AF_INET6;
	inet_pton(AF_INET6, SSDP_IPV6_SITELOCAL, &destAddr6->sin6_addr);
	destAddr6->sin6_port = htons(SSDP_PORT);
	destAddr6->sin6_scope_id = gIF_INDEX;
#endif

	/* add search criteria to list */
	HandleLock();
	if (GetClientHandleInfo(&handle, &ctrlpt_info) != HND_CLIENT) {
		HandleUnlock();
		return UPNP_E_INTERNAL_ERROR;
	}
	newArg = (SsdpSearchArg *) malloc(sizeof(SsdpSearchArg));
	newArg->searchTarget = strdup(St);
	newArg->cookie = Cookie;
	newArg->requestType = requestType;
	id = (int *)malloc(sizeof(int));
	TPJobInit(&job, (start_routine) searchExpired, id);
	TPJobSetPriority(&job, MED_PRIORITY);
	TPJobSetFreeFunction(&job, (free_routine) free);
	/* Schedule a timeout event to remove search Arg */
	TimerThreadSchedule(&gTimerThread, timeTillRead,
			    REL_SEC, &job, SHORT_TERM, id);
	newArg->timeoutEventId = *id;
	ListAddTail(&ctrlpt_info->SsdpSearchList, newArg);
	HandleUnlock();
	/* End of lock */

	FD_ZERO(&wrSet);
	if (gSsdpReqSocket4 != INVALID_SOCKET) {
		setsockopt(gSsdpReqSocket4, IPPROTO_IP, IP_MULTICAST_IF,
			   (char *)&addrv4, sizeof(addrv4));
		FD_SET(gSsdpReqSocket4, &wrSet);
		max_fd = max(max_fd, gSsdpReqSocket4);
	}
#ifdef UPNP_ENABLE_IPV6
	if (gSsdpReqSocket6 != INVALID_SOCKET) {
		setsockopt(gSsdpReqSocket6, IPPROTO_IPV6, IPV6_MULTICAST_IF,
			   (char *)&gIF_INDEX, sizeof(gIF_INDEX));
		FD_SET(gSsdpReqSocket6, &wrSet);
		max_fd = max(max_fd, gSsdpReqSocket6);
	}
#endif
	ret = select(max_fd + 1, NULL, &wrSet, NULL, NULL);
	if (ret == -1) {
		strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN);
		UpnpPrintf(UPNP_INFO, SSDP, __FILE__, __LINE__,
			   "SSDP_LIB: Error in select(): %s\n", errorBuffer);
		shutdown(gSsdpReqSocket4, SD_BOTH);
		UpnpCloseSocket(gSsdpReqSocket4);
#ifdef UPNP_ENABLE_IPV6
		shutdown(gSsdpReqSocket6, SD_BOTH);
		UpnpCloseSocket(gSsdpReqSocket6);
#endif
		return UPNP_E_INTERNAL_ERROR;
	}
#ifdef UPNP_ENABLE_IPV6
	if (gSsdpReqSocket6 != INVALID_SOCKET &&
	    FD_ISSET(gSsdpReqSocket6, &wrSet)) {
		int NumCopy = 0;

		while (NumCopy < NUM_SSDP_COPY) {
			UpnpPrintf(UPNP_INFO, SSDP, __FILE__, __LINE__,
				   ">>> SSDP SEND M-SEARCH >>>\n%s\n",
				   ReqBufv6UlaGua);
			sendto(gSsdpReqSocket6,
			       ReqBufv6UlaGua, strlen(ReqBufv6UlaGua), 0,
			       (struct sockaddr *)&__ss_v6,
			       sizeof(struct sockaddr_in6));
			NumCopy++;
			imillisleep(SSDP_PAUSE);
		}
		NumCopy = 0;
		inet_pton(AF_INET6, SSDP_IPV6_LINKLOCAL, &destAddr6->sin6_addr);
		while (NumCopy < NUM_SSDP_COPY) {
			UpnpPrintf(UPNP_INFO, SSDP, __FILE__, __LINE__,
				   ">>> SSDP SEND M-SEARCH >>>\n%s\n",
				   ReqBufv6);
			sendto(gSsdpReqSocket6,
			       ReqBufv6, strlen(ReqBufv6), 0,
			       (struct sockaddr *)&__ss_v6,
			       sizeof(struct sockaddr_in6));
			NumCopy++;
			imillisleep(SSDP_PAUSE);
		}
	}
#endif /* IPv6 */
	if (gSsdpReqSocket4 != INVALID_SOCKET &&
	    FD_ISSET(gSsdpReqSocket4, &wrSet)) {
		int NumCopy = 0;
		while (NumCopy < NUM_SSDP_COPY) {
			UpnpPrintf(UPNP_INFO, SSDP, __FILE__, __LINE__,
				   ">>> SSDP SEND M-SEARCH >>>\n%s\n",
				   ReqBufv4);
			sendto(gSsdpReqSocket4,
			       ReqBufv4, strlen(ReqBufv4), 0,
			       (struct sockaddr *)&__ss_v4,
			       sizeof(struct sockaddr_in));
			NumCopy++;
			imillisleep(SSDP_PAUSE);
		}
	}

	return 1;
}
コード例 #14
0
/************************************************************************
 * Function: TimerThreadSchedule
 * 
 *  Description:
 *     Schedules an event to run at a specified time.
 *
 *  Parameters:
 *             timer - valid timer thread pointer.
 *             time_t - time of event.
 *                      either in absolute seconds,
 *                      or relative seconds in the future.
 *             timeoutType - either ABS_SEC, or REL_SEC.
 *                           if REL_SEC, then the event
 *                           will be scheduled at the
 *                           current time + REL_SEC.
 *             
 *             func - function to schedule
 *             arg - argument to function
 *             priority - priority of job.
 *             id - id of timer event. (out)
 *  Return:
 *            0 on success, nonzero on failure
 *			  EOUTOFMEM if not enough memory to schedule job
 ************************************************************************/
int
TimerThreadSchedule( TimerThread * timer,
                     time_t timeout,
                     TimeoutType type,
                     ThreadPoolJob * job,
                     Duration duration,
                     int *id )
{

    int rc = EOUTOFMEM;
    int found = 0;
    int tempId = 0;

    ListNode *tempNode = NULL;
    TimerEvent *temp = NULL;
    TimerEvent *newEvent = NULL;

    assert( timer != NULL );
    assert( job != NULL );

    if( ( timer == NULL ) || ( job == NULL ) ) {
        return EINVAL;
    }

    CalculateEventTime( &timeout, type );
    ithread_mutex_lock( &timer->mutex );

    if( id == NULL )
        id = &tempId;

    ( *id ) = INVALID_EVENT_ID;

    newEvent = CreateTimerEvent( timer, job, duration, timeout,
                                 timer->lastEventId );

    if( newEvent == NULL ) {
        ithread_mutex_unlock( &timer->mutex );
        return rc;
    }

    tempNode = ListHead( &timer->eventQ );
    //add job to Q
    //Q is ordered by eventTime
    //with the head of the Q being the next event

    while( tempNode != NULL ) {
        temp = ( TimerEvent * ) tempNode->item;
        if( temp->eventTime >= timeout )
        {

            if( ListAddBefore( &timer->eventQ, newEvent, tempNode ) !=
                NULL )
                rc = 0;
            found = 1;
            break;

        }
        tempNode = ListNext( &timer->eventQ, tempNode );
    }

    //add to the end of Q
    if( !found ) {

        if( ListAddTail( &timer->eventQ, newEvent ) != NULL )
            rc = 0;

    }
    //signal change in Q
    if( rc == 0 ) {

        ithread_cond_signal( &timer->condition );
    } else {
        FreeTimerEvent( timer, newEvent );
    }
    ( *id ) = timer->lastEventId++;
    ithread_mutex_unlock( &timer->mutex );

    return rc;
}
コード例 #15
0
LOCAL BOOL SetupMacro(LPQUEUEITEM lpQueueItem)
/***********************************************************************/
{
	LPCMDPKT		lpCmdPkt;
	FNAME		   	szFileName;

	lpCmdPkt = CreatePacket(IDS_CMD_LOADFILE, &lpQueueItem->parms, TRUE);
	if (!lpCmdPkt)
		goto MemError;
	ListAddHead(&lpQueueItem->PacketList, lpCmdPkt);

	// create the new filename
	// add a save command to the end if necessary
	if (Macro.BatchSave == IDC_SAVETOORIGINAL)
		lstrcpy(szFileName, lpQueueItem->szFileName);
	else
	if (Macro.BatchSave == IDC_SAVETODIR)
	{
		lstrcpy(szFileName, Macro.BatchDir);
		lstrcat(szFileName, filename(lpQueueItem->szFileName));
	}
	else
	if (Macro.BatchSave == IDC_SAVETOALBUM)
	{
		lstrcpy(szFileName, Browser.AlbumFileDir);
		lstrcat(szFileName, filename(lpQueueItem->szFileName));
	}

	// if we are changing the file type, then change the extension
	if (Macro.fBatchChangeType &&
		(Macro.BatchSave == IDC_SAVETODIR || Macro.BatchSave == IDC_SAVETOALBUM))
	{
		STRING szExt;

		LookupExtension(LocalFileType(Macro.BatchFileType), szExt);
		stripext(szFileName);
		lstrcat(szFileName, szExt);
	}

	// check to make sure we are not saving to PCD and overwrite warning
	if (Macro.BatchSave != IDC_NOSAVE)
	{
		if (!CheckPCDSave(szFileName))
			return(FALSE);
		if (Macro.BatchSave != IDC_SAVETOORIGINAL)
		{
			if (FileExists(szFileName))
			{
				if (AstralOKCancel (IDS_OVERWRITEIMAGE, (LPTSTR)szFileName) != IDOK)
					return(FALSE);
			}
		}

	}

	if (Macro.BatchSave == IDC_SAVETOALBUM)
	{
		// get a path name from the browser
		SAVETOALBUM_PARMS parms;

		lstrcpy(parms.szAlbum, Macro.BatchAlbum);
		lstrcpy(parms.szFileName, szFileName);
	  	parms.idFileType = 	GetPPFileType(parms.szFileName);
		parms.idDataType = 0;
		parms.EPSOptions = EPSOptions;
		parms.TIFFOptions = TIFFOptions;
		parms.TGAOptions = TGAOptions;
		parms.JPEGOptions = JPEGOptions;
		parms.PPFFOptions = PPFFOptions;
		parms.AVIOptions = AVIOptions;

		// create a command list for the load command
		lpCmdPkt = CreatePacket(IDS_CMD_SAVETOALBUM, &parms, TRUE);
		if (!lpCmdPkt)
			goto MemError;
		ListAddTail(&lpQueueItem->PacketList, lpCmdPkt);
	}
	else
	if (Macro.BatchSave != IDC_NOSAVE)
	{
		SAVEFILE_PARMS parms;

		lstrcpy(parms.szFileName, szFileName);
		parms.idFileType = 	GetPPFileType(parms.szFileName);
		parms.idDataType = 0;
		parms.EPSOptions = EPSOptions;
		parms.TIFFOptions = TIFFOptions;
		parms.TGAOptions = TGAOptions;
		parms.JPEGOptions = JPEGOptions;
		parms.PPFFOptions = PPFFOptions;
		parms.AVIOptions = AVIOptions;

		// create a command list for the load command
		lpCmdPkt = CreatePacket(IDS_CMD_SAVEFILE, &parms, TRUE);
		if (!lpCmdPkt)
			goto MemError;
		ListAddTail(&lpQueueItem->PacketList, lpCmdPkt);
	}
	if (Macro.fBatchClose)
	{
		CMD_PARMS parms;

		// create a command list for the load command
		lpCmdPkt = CreatePacket(IDS_CMD_CLOSE, &parms, TRUE);
		if (!lpCmdPkt)
			goto MemError;
		ListAddTail(&lpQueueItem->PacketList, lpCmdPkt);
	}
	return(TRUE);

MemError:
	Message(IDS_EMEMALLOC);
	return(FALSE);
}
コード例 #16
0
BOOL PlayMacro(LPCMDLIST lpCmdList, LPTSTR lpFileName, int nRepeat,
				BOOL fSequenceAll, LPLIST lpMacroList, HWND hParent,
				int PhotoCDResOverride, LPTSTR lpMacroName)
/***********************************************************************/
{
LPIMAGE lpImage;
LPCMDLIST lpNewList;
int nActivates, iCount;
ITEMID idCommand;
STRING szString, szAppName;
BOOL fError;
BOOL fSequence, fCmdSequence, fCopyPackets;
LIST MacroList;
LPCMDPKT lpCmdPkt, lpNextPkt;
MACROSETUP Setup;
COMMAND_TYPE CommandType;
HWND hDlg = NULL;

lpAbortProc = NULL;
if (!hParent)
	hParent = PictPubApp.Get_hWndAstral();

// see if we need to copy our packets
fCopyPackets = nRepeat > 1;

if (!lpMacroList)
	{
	// read in the entire macro file for faster processing
	if (!ReadMacro(lpFileName, &MacroList))
		return(FALSE);
	lpMacroList = &MacroList;
	}

// count the number of activates in the macro file
// because it affects sequencing
nActivates = CountType(lpMacroList, CT_ACTIVATE);

// turn of macro play mode and tell the world
MacroMode = MM_PLAY;
if ( AstralStrEx( IDS_APPNAME, szAppName, sizeof(szAppName) ) )
	{
	if ( AstralStrEx( IDS_MACROPLAY, szString, sizeof(szString) ) )
		{
		lstrcat( szAppName, szString );
		SetWindowText( PictPubApp.Get_hWndAstral(), szAppName );
		}
	}

// reset untitled number so that if a macro is played it
// can deal with untitled images the same
Control.UntitledNo = 0;

// If no command list passed in to work on (Macro Batch Mode)
// then get command list for active image
if (!lpCmdList)
	{
	if (lpImage = GetActiveImage())
		lpCmdList = lpImage->lpCmdList;
	else
		lpCmdList = NULL;
	}

// See if the macro contains any low res loads and
// if so ask to user if he'd like to convert them
// to hi res loads and if so do the convert
if (FindCommand(lpMacroList, IDS_CMD_LOWRESLOAD))
	if (AstralAffirm(IDS_CONVERTLOWRES))
		if (!ConvertLowResLoad(lpMacroList))
			{
			DestroyPacketList(lpMacroList);
			return(FALSE);
			}

// disable all mouse and keyboard input during macro play
EnableWindow(hParent, FALSE);

// if not in a threading environment and caller wants us
// to display a progress dialog, then set it up and do it
if (!Control.UseThreading)
	{
	iCount = ListGetCount(lpMacroList) - nActivates;
	iCount *= nRepeat;
	Setup.iTotal = iCount;
	Setup.idDialog = IDD_MACRO_STATUS;
	Setup.lpFileName = NULL;
    hDlg = AstralDlgParam( YES, PictPubApp.GetResourceHandle(), hParent, IDD_MACRO_STATUS,
						DlgMacroStatusProc,
						(LPARAM)(LPVOID)&Setup );
	if (hDlg)
		{
		if (lpMacroName)
			{
			STRING szString;

			GetWindowText(hDlg, szString, sizeof(szString));
			lstrcat(szString, _T(" - "));
			lstrcat(szString, lpMacroName);
			SetWindowText(hDlg, szString);
			}

		UpdateWindow(hDlg);
		}
	}

// Repeat macro nRepeat number of times
fError = FALSE;
while (--nRepeat >= 0 && !fError)
	{
	if (lpAbortProc && (*lpAbortProc)())
		break;
	// back to beginning of macro file
	lpNextPkt = (LPCMDPKT)ListGetHead(lpMacroList);

	// initialize sequencing
	fSequence = fSequenceAll;

	while (!fError && lpNextPkt)
		{
		if (lpAbortProc && (*lpAbortProc)())
			{
			fError = TRUE;
			break;
			}
		// get the packet to work on
		if (fCopyPackets)
			{
			lpCmdPkt = CopyPacket(lpNextPkt);
			if (!lpCmdPkt)
				{
				fError = TRUE;
				break;
				}
			}
		else
			{
			ListUnlink(lpMacroList, lpNextPkt);
			lpCmdPkt = lpNextPkt;
			}

		// get command id and parms for this command
		idCommand = lpCmdPkt->idCommand;

		// Find out whether this command requires sequencing
		// set it here, so command can change it if needed before
		// we actually set fSequence
		fCmdSequence = GetCommandSequence(idCommand);
		CommandType = GetCommandType(idCommand);

		// Handle the different types of commands
		switch (CommandType)
			{
			case CT_LOAD:
				// create new command list for load
				lpNewList = CreateCommandList();
				if (lpNewList)
					{
					ListAddTail(&lpNewList->PacketList, lpCmdPkt);

					// if we already have a command list containing commands,
					// kick off the execution of those commands before we
					// switch to the new command list
					if (lpCmdList && !ListIsEmpty(&lpCmdList->PacketList))
						{
						PlaybackCommands(lpCmdList);
						// if some command in the command list affects
						// sequencing force the whole command list to
						// be processed
						if (fSequence)
							{
							FlushCommands(lpCmdList);
							fSequence = fSequenceAll;
							}
						}
					// setup new command list for us to work with
					lpCmdList = lpNewList;
					lpCmdList->PhotoCDResOverride = PhotoCDResOverride;

					// If there are any activates in this macro make sure a
					// command that creates an image processes immediately
					if (nActivates)
						{
						PlaybackCommands(lpCmdList);
						FlushCommands(lpCmdList);
						fSequence = fSequenceAll;
						fCmdSequence = NO; // already sequenced
						}
					}
				break;

			case CT_COPY:
				// Make sure we have a command list to work with
				if (!lpCmdList)
					{
				 	Message(IDS_NOIMAGETOWORKON);
					fError = TRUE;
					break;
					}
				// Just add this command to the command list
				ListAddTail(&lpCmdList->PacketList, lpCmdPkt);

				// If there are any activates in this macro make sure a
				// command that creates an image processes immediately
				if (nActivates)
					{
					PlaybackCommands(lpCmdList);
					FlushCommands(lpCmdList);
					fSequence = fSequenceAll;
					fCmdSequence = NO; // already sequenced
					}
				break;

			case CT_SAVE:
			case CT_EDIT:
			case CT_MASK:
			case CT_MODE:
			case CT_EDITUNDO:
			case CT_MASKUNDO:
			case CT_EDITOBJ:
			case CT_CLOSE:
				// Make sure we have a command list to work with
				if (!lpCmdList)
					{
				 	Message(IDS_NOIMAGETOWORKON);
					fError = TRUE;
					break;
					}
				if (CommandType == CT_SAVE)
					{
					PlaybackCommands(lpCmdList);
					if (!lpCmdList->ThreadData.lpImage)
						{
				 		Message(IDS_NOIMAGETOWORKON);
						fError = TRUE;
						break;
						}
					}

				// Just add this command to the command list
				ListAddTail(&lpCmdList->PacketList, lpCmdPkt);
				if (CommandType != CT_CLOSE)
					break;

			case CT_ACTIVATE:
				// Program or commands that affect window activation
				// are processed here
				switch (idCommand)
					{
					case IDS_CMD_CLOSE:
					case IDS_CMD_ACTIVATEWINDOW:
						{
						// if we already have a command list containing commands,
						// kick of the execution of those commands before we
						// switch to the new command list
						if (lpCmdList && !ListIsEmpty(&lpCmdList->PacketList))
							{
							PlaybackCommands(lpCmdList);
							// if some command in the command list affects
							// sequencing force the whole command list to
							// be processed
							if (fSequence)
								{
								FlushCommands(lpCmdList);
								fSequence = fSequenceAll;
								}
							}
						// if this was a close command, then wack the command list pointer
						if (idCommand == IDS_CMD_CLOSE)
							lpCmdList = NULL;
						else
							{
							// now process the activate and get a new command list
							lpNewList = ProgActivateWindow(
									(LPACTIVATEWINDOW_PARMS)lpCmdPkt->lpParms);
							// setup the new command list if we got one
							if (lpNewList)
								lpCmdList = lpNewList;
							else
								{
								CommandError(idCommand);
								fError = TRUE;
								}
							// activate don't go through command processing
							// so we have to free it up here
							FreeUpPacket(lpCmdPkt);
							}
						}
					break;

					default:
					break;
					}
				break;

			default:
				break;
			}
		// if command just handled requires sequencing
		// set sequencing flag
		if (fCmdSequence)
			fSequence = YES;
		if (fCopyPackets)
			// get next command packet in macro list
			lpNextPkt = (LPCMDPKT)ListGetNext(lpNextPkt);
		else
			// head of list will be next one if we're not copying
			lpNextPkt = (LPCMDPKT)ListGetHead(lpMacroList);
		}
	}
// get rid of macro list
DestroyPacketList(lpMacroList);

// if we already have a command list containing commands,
// kick off the execution of those commands
if (lpCmdList && !ListIsEmpty(&lpCmdList->PacketList))
	{
	PlaybackCommands(lpCmdList);
	if (fSequenceAll)
		FlushCommands(lpCmdList);
	}

// turn off the macro mode
EnableWindow(hParent, TRUE);
if ( AstralStrEx( IDS_APPNAME, szAppName, sizeof(szAppName) ) )
	SetWindowText( PictPubApp.Get_hWndAstral(), szAppName );
// if we have a progress dialog, nuke it
if (hDlg)
	AstralDlgEnd(hDlg, TRUE);
// if we are display the macro status for another modal dialog 
// make sure the main app stuff is still disabled
if (hParent != PictPubApp.Get_hWndAstral())
	{
	EnableOverlappedWindow( PictPubApp.Get_hWndAstral(), FALSE );
	EnableWindow(PictPubApp.Get_hWndAstral(), FALSE);
	}
MacroMode = MM_NONE;
return(TRUE);
}
コード例 #17
0
void PlayBatchMacro(LPLIST lpQueueList)
/***********************************************************************/
{
	LPQUEUEITEM 	lpQueueItem = NULL;
	LPMACROITEM 	lpMacroItem;
	FNAME 			szFileName;
	LIST 			TempList;
	BOOL			fError = TRUE;

	fPCDNotice = FALSE;
	while (TRUE)
	{
		if (lpQueueItem)
			lpQueueItem = (LPQUEUEITEM)ListGetNext(lpQueueItem);
		else
			lpQueueItem = (LPQUEUEITEM)ListGetHead(lpQueueList);

		if (!lpQueueItem)
		{
			fError = FALSE;
			break;
		}

		ListInit(&lpQueueItem->PacketList);

		// create a command list for the load command
		if (!CreateLoadFileParms(0, lpQueueItem->szFileName, TRUE,
 								&lpQueueItem->cmsInfo,
								&lpQueueItem->PhotoCDResOverride,
								&lpQueueItem->parms))
			continue;

		lpMacroItem = NULL;
		while (TRUE)
		{
			if (lpMacroItem)
				lpMacroItem = (LPMACROITEM)ListGetNext(lpMacroItem);
			else
				lpMacroItem = (LPMACROITEM)ListGetHead(&lpQueueItem->MacroList);
			if (!lpMacroItem)
				break;

			if ( !LookupExtFile( lpMacroItem->szMacro, szFileName, IDN_MACRO ) )
				continue;

			// read in the entire macro file for faster processing
			if (!ReadMacro(szFileName, &TempList))
				continue;
			if (MacroAnyLoadCommands(&TempList))
    		{
	    		Message(IDS_BADBATCHMACRO);
				DestroyPacketList(&TempList);
				continue;
		    }
			ListAddTail(&lpQueueItem->PacketList, ListGetHead(&TempList));
		}

		if (!SetupMacro(lpQueueItem))
			break;
	}
	if (!fError)
	{
		if (EnableLogging(TRUE))
		{
			lpQueueItem = NULL;
			while (!fError)
			{
				if (lpQueueItem)
					lpQueueItem = (LPQUEUEITEM)ListGetNext(lpQueueItem);
				else
					lpQueueItem = (LPQUEUEITEM)ListGetHead(lpQueueList);
				if (!lpQueueItem)
					break;
				if (!PlayMacro(NULL, NULL, 1, NO, &lpQueueItem->PacketList, NULL, lpQueueItem->PhotoCDResOverride))
					break;
			}
		 	EnableLogging(FALSE);
		}
	}

	lpQueueItem = NULL;
	while (TRUE)
	{
		if (lpQueueItem)
			lpQueueItem = (LPQUEUEITEM)ListGetNext(lpQueueItem);
		else
			lpQueueItem = (LPQUEUEITEM)ListGetHead(lpQueueList);
		if (!lpQueueItem)
			break;

		DestroyPacketList(&lpQueueItem->PacketList);
		DestroyPtrList(&lpQueueItem->MacroList);
	}
	DestroyPtrList(lpQueueList);
}
コード例 #18
0
ファイル: gena_device.c プロジェクト: mrjimenez/pupnp
/* We take ownership of propertySet and will free it */
static int genaInitNotifyCommon(
	UpnpDevice_Handle device_handle,
	char *UDN,
	char *servId,
	DOMString propertySet,
	const Upnp_SID sid)
{
	int ret = GENA_SUCCESS;
	int line = 0;

	int *reference_count = NULL;
	char *UDN_copy = NULL;
	char *servId_copy = NULL;
	char *headers = NULL;
	notify_thread_struct *thread_struct = NULL;

	subscription *sub = NULL;
	service_info *service = NULL;
	struct Handle_Info *handle_info;
	ThreadPoolJob *job = NULL;

	UpnpPrintf(UPNP_INFO, GENA, __FILE__, __LINE__,
		"GENA BEGIN INITIAL NOTIFY COMMON");

	job = (ThreadPoolJob *)malloc(sizeof(ThreadPoolJob));
	if (job == NULL) {
		line = __LINE__;
		ret = UPNP_E_OUTOF_MEMORY;
		goto ExitFunction;
	}
	memset(job, 0, sizeof(ThreadPoolJob));

	reference_count = (int *)malloc(sizeof (int));
	if (reference_count == NULL) {
		line = __LINE__;
		ret = UPNP_E_OUTOF_MEMORY;
		goto ExitFunction;
	}
	*reference_count = 0;
	
	UDN_copy = strdup(UDN);
	if (UDN_copy == NULL) {
		line = __LINE__;
		ret = UPNP_E_OUTOF_MEMORY;
		goto ExitFunction;
	}

	servId_copy = strdup(servId);
	if (servId_copy == NULL) {
		line = __LINE__;
		ret = UPNP_E_OUTOF_MEMORY;
		goto ExitFunction;
	}

	HandleLock();

	if (GetHandleInfo(device_handle, &handle_info) != HND_DEVICE) {
		line = __LINE__;
		ret = GENA_E_BAD_HANDLE;
		goto ExitFunction;
	}

	service = FindServiceId(&handle_info->ServiceTable, servId, UDN);
	if (service == NULL) {
		line = __LINE__;
		ret = GENA_E_BAD_SERVICE;
		goto ExitFunction;
	}
	UpnpPrintf(UPNP_INFO, GENA, __FILE__, __LINE__,
		"FOUND SERVICE IN INIT NOTFY: UDN %s, ServID: %s",
		UDN, servId);

	sub = GetSubscriptionSID(sid, service);
	if (sub == NULL || sub->active) {
		line = __LINE__;
		ret = GENA_E_BAD_SID;
		goto ExitFunction;
	}
	UpnpPrintf( UPNP_INFO, GENA, __FILE__, __LINE__,
		"FOUND SUBSCRIPTION IN INIT NOTIFY: SID %s", sid);
	sub->active = 1;

	headers = AllocGenaHeaders(propertySet);
	if (headers == NULL) {
		line = __LINE__;
		ret = UPNP_E_OUTOF_MEMORY;
		goto ExitFunction;
	}

	/* schedule thread for initial notification */

	thread_struct = (notify_thread_struct *)malloc(sizeof (notify_thread_struct));
	if (thread_struct == NULL) {
		line = __LINE__;
		ret = UPNP_E_OUTOF_MEMORY;
	} else {
		*reference_count = 1;
		thread_struct->servId = servId_copy;
		thread_struct->UDN = UDN_copy;
		thread_struct->headers = headers;
		thread_struct->propertySet = propertySet;
		memset(thread_struct->sid, 0, sizeof(thread_struct->sid));
		strncpy(thread_struct->sid, sid,
			sizeof(thread_struct->sid) - 1);
		thread_struct->ctime = time(0);
		thread_struct->reference_count = reference_count;
		thread_struct->device_handle = device_handle;

		TPJobInit(job, (start_routine)genaNotifyThread, thread_struct);
		TPJobSetFreeFunction(job, (free_routine)free_notify_struct);
		TPJobSetPriority(job, MED_PRIORITY);

		ret = ThreadPoolAdd(&gSendThreadPool, job, NULL);
		if (ret != 0) {
			if (ret == EOUTOFMEM) {
				line = __LINE__;
				ret = UPNP_E_OUTOF_MEMORY;
			}
		} else {
			ListNode *node = ListAddTail(&sub->outgoing, job);
			if (node != NULL) {
				((ThreadPoolJob *)node->item)->jobId = STALE_JOBID;
				line = __LINE__;
				ret = GENA_SUCCESS;
			} else {
				line = __LINE__;
				ret = UPNP_E_OUTOF_MEMORY;
			}
		}
	}

ExitFunction:
	if (ret != GENA_SUCCESS) {
		free(job);
		free(thread_struct);
		free(headers);
		ixmlFreeDOMString(propertySet);
		free(servId_copy);
		free(UDN_copy);
		free(reference_count);
	}

	HandleUnlock();

	UpnpPrintf(UPNP_INFO, GENA, __FILE__, line,
		"GENA END INITIAL NOTIFY COMMON, ret = %d",
		ret);

	return ret;
}
コード例 #19
0
ファイル: gena_device.c プロジェクト: mrjimenez/pupnp
/* We take ownership of propertySet and will free it */
static int genaNotifyAllCommon(
	UpnpDevice_Handle device_handle,
	char *UDN,
	char *servId,
	DOMString propertySet)
{
	int ret = GENA_SUCCESS;
	int line = 0;

	int *reference_count = NULL;
	char *UDN_copy = NULL;
	char *servId_copy = NULL;
	char *headers = NULL;
	notify_thread_struct *thread_struct = NULL;

	subscription *finger = NULL;
	service_info *service = NULL;
	struct Handle_Info *handle_info;

	UpnpPrintf(UPNP_INFO, GENA, __FILE__, __LINE__,
		"GENA BEGIN NOTIFY ALL COMMON");

	/* Keep this allocation first */
	reference_count = (int *)malloc(sizeof (int));
	if (reference_count == NULL) {
		line = __LINE__;
		ret = UPNP_E_OUTOF_MEMORY;
		goto ExitFunction;
	}
	*reference_count = 0;
	
	UDN_copy = strdup(UDN);
	if (UDN_copy == NULL) {
		line = __LINE__;
		ret = UPNP_E_OUTOF_MEMORY;
		goto ExitFunction;
	}

	servId_copy = strdup(servId);
	if( servId_copy == NULL ) {
		line = __LINE__;
		ret = UPNP_E_OUTOF_MEMORY;
		goto ExitFunction;
	}

	headers = AllocGenaHeaders(propertySet);
	if (headers == NULL) {
		line = __LINE__;
		ret = UPNP_E_OUTOF_MEMORY;
		goto ExitFunction;
	}

	HandleLock();

	if (GetHandleInfo(device_handle, &handle_info) != HND_DEVICE) {
		line = __LINE__;
		ret = GENA_E_BAD_HANDLE;
	} else {
		service = FindServiceId(&handle_info->ServiceTable, servId, UDN);
		if (service != NULL) {
			finger = GetFirstSubscription(service);
			while (finger) {
				ThreadPoolJob *job = NULL;
				ListNode *node;

				thread_struct = (notify_thread_struct *)malloc(sizeof (notify_thread_struct));
				if (thread_struct == NULL) {
					line = __LINE__;
					ret = UPNP_E_OUTOF_MEMORY;
					break;
				}

				(*reference_count)++;
				thread_struct->reference_count = reference_count;
				thread_struct->UDN = UDN_copy;
				thread_struct->servId = servId_copy;
				thread_struct->headers = headers;
				thread_struct->propertySet = propertySet;
				memset(thread_struct->sid, 0,
					sizeof(thread_struct->sid));
				strncpy(thread_struct->sid, finger->sid,
					sizeof(thread_struct->sid) - 1);
				thread_struct->ctime = time(0);
				thread_struct->device_handle = device_handle;

				maybeDiscardEvents(&finger->outgoing);
				job = (ThreadPoolJob *)malloc(sizeof(ThreadPoolJob));
				if (job == NULL) {
					line = __LINE__;
					ret = UPNP_E_OUTOF_MEMORY;
					break;
				}
				memset(job, 0, sizeof(ThreadPoolJob));
				TPJobInit(job, (start_routine)genaNotifyThread, thread_struct);
				TPJobSetFreeFunction(job, (free_routine)free_notify_struct);
				TPJobSetPriority(job, MED_PRIORITY);
				node = ListAddTail(&finger->outgoing, job);

				/* If there is only one element on the list (which we just
				   added), need to kickstart the threadpool */
				if (ListSize(&finger->outgoing) == 1) {
					ret = ThreadPoolAdd(&gSendThreadPool, job, NULL);
					if (ret != 0) {
						line = __LINE__;
						if (ret == EOUTOFMEM) {
							line = __LINE__;
							ret = UPNP_E_OUTOF_MEMORY;
						}
						break;
					}
					if (node) {
						((ThreadPoolJob *)(node->item))->jobId = STALE_JOBID;
					}
				}
				finger = GetNextSubscription(service, finger);
			}
		} else {
			line = __LINE__;
			ret = GENA_E_BAD_SERVICE;
		}
	}

ExitFunction:
	/* The only case where we want to free memory here is if the
	   struct was never queued. Else, let the normal cleanup take place.
	   reference_count is allocated first so it's ok to do nothing if it's 0
	*/
	if (reference_count && *reference_count == 0) {
		free(headers);
		ixmlFreeDOMString(propertySet);
		free(servId_copy);
		free(UDN_copy);
		free(reference_count);
	}

	HandleUnlock();

	UpnpPrintf(UPNP_INFO, GENA, __FILE__, line,
		"GENA END NOTIFY ALL COMMON, ret = %d",
		ret);

	return ret;
}
コード例 #20
0
/****************************************************************************
 * Function: ThreadPoolAdd
 *
 *  Description:
 *      Adds a job to the thread pool.
 *      Job will be run as soon as possible.
 *  Parameters:
 *      tp - valid thread pool pointer
 *      func - ThreadFunction to run
 *      arg - argument to function.
 *      priority - priority of job.
 *      jobId - id of job
 *      duration - whether or not this is a persistent thread
 *      free_function - function to use when freeing argument
 *  Returns:
 *      0 on success, nonzero on failure
 *      EOUTOFMEM if not enough memory to add job.
 *****************************************************************************/
int ThreadPoolAdd( ThreadPool *tp, ThreadPoolJob *job, int *jobId )
{
	int rc = EOUTOFMEM;

	int tempId = -1;
	int totalJobs;

	ThreadPoolJob *temp = NULL;

	assert( tp != NULL );
	assert( job != NULL );
	if( ( tp == NULL ) || ( job == NULL ) ) {
		return EINVAL;
	}

	ithread_mutex_lock( &tp->mutex );

	assert( job->priority == LOW_PRIORITY ||
	job->priority == MED_PRIORITY ||
	job->priority == HIGH_PRIORITY );

	totalJobs = tp->highJobQ.size + tp->lowJobQ.size + tp->medJobQ.size;
	if (totalJobs >= tp->attr.maxJobsTotal) {
		fprintf(stderr, "total jobs = %d, too many jobs", totalJobs);
		ithread_mutex_unlock( &tp->mutex );
		return rc;
	}

	if( jobId == NULL ) {
		jobId = &tempId;
	}
	*jobId = INVALID_JOB_ID;

	temp = CreateThreadPoolJob( job, tp->lastJobId, tp );
	if( temp == NULL ) {
		ithread_mutex_unlock( &tp->mutex );
		return rc;
	}

	if( job->priority == HIGH_PRIORITY ) {
		if( ListAddTail( &tp->highJobQ, temp ) ) {
			rc = 0;
		}
	} else if( job->priority == MED_PRIORITY ) {
		if( ListAddTail( &tp->medJobQ, temp ) ) {
			rc = 0;
		}
	} else {
		if( ListAddTail( &tp->lowJobQ, temp ) ) {
			rc = 0;
		}
	}

	// AddWorker if appropriate
	AddWorker( tp );

	// Notify a waiting thread
	if( rc == 0 ) {
		ithread_cond_signal( &tp->condition );
	} else {
		FreeThreadPoolJob( tp, temp );
	}

	*jobId = tp->lastJobId++;

	ithread_mutex_unlock( &tp->mutex );

	return rc;
}