euc.previous_interaction = HOME;
void *start_eu(void *data){	double usmd;	time_t user_start;	struct timeval rt0, rt1;	double response_time;	int i;	struct eu_context_t euc;	int rc;	struct timespec think_time, rem;	int retry;	extern int errno;#ifdef PHASE2	int *port;	port = (int *) data;#endif /* PHASE2 */	/* Random number generator must be seeded per thread in Linux. */	srand(time(NULL) + pthread_self());	/*	 * Just zero out the entire structure since it's all contiguous and I use	 * 0 as unknown values (defined in common.h) and so I don't have to	 * remember which variables to initialize individually.	 */	bzero(&euc, sizeof(euc));#ifdef PHASE1	/* Connect to the database. */	while (odbc_connect(&euc.odbcc) != W_OK)	{		/*		 * Attempt to connect to the database every 10 seconds, if there		 * is a failure.		 */		sleep(10);		LOG_ERROR_MESSAGE("cannot connect to database");	}#ifdef SEARCH_RESULTS_CACHE	if ((euc.cache_s = _connect(cache_host, cache_port)) == -1)	{		printf("connect to cache failed\n");		LOG_ERROR_MESSAGE("connect to cache failed");		return;	}#endif#endif /* PHASE1 */#ifdef PHASE2	if ((euc.s = _connect(tm_address, *port)) == -1)	{		printf("connect to appServer failed\n");		LOG_ERROR_MESSAGE("connect failed");		return;	}#endif /* PHASE2 */	/* Main loop for the user logic. */	retry = 0;	do	{		/* Determine this users minimum duration and note the start time. */		usmd = get_usmd();		time(&user_start);		/* The Home interaction is always first. */		euc.interaction = HOME;		euc.sc_id = UNKNOWN_SHOPPING_CART;		euc.first_interaction=TRUE;		/* do Home interaction, retry RETRY time if error happens */		do		{			/* Get the time before the interaction is executed. */			if (gettimeofday(&rt0, NULL) == -1)			{				perror("gettimeofday");			}			rc = do_interaction(&euc);						/* Get the time after the interaction has executed. */			if (gettimeofday(&rt1, NULL) == -1)			{				perror("gettimeofday");			}			if (rc == W_ERROR)			{				LOG_ERROR_MESSAGE("error executing %s",					interaction_short_name[euc.interaction]);				dump_interaction_data(&euc);				/* Log the error */				pthread_mutex_lock(&mutex_mix_log);				fprintf(log_mix, "%d,ER,%f,%d\n",					time(NULL), (double)retry, pthread_self());				fflush(log_mix);				pthread_mutex_unlock(&mutex_mix_log);#ifdef PHASE1				/*				 * If an error occurs, reconnect since it could be a dropped				 * connection causing the error.				 */				odbc_disconnect(&euc.odbcc);				odbc_connect(&euc.odbcc);#endif /* PHASE1 */				/* an error can be caused by db transaction 				 * failure, or socket error 				 */				/* If an error occurs, sleep for 10 seconds and try again. */				sleep(10);			}			retry++;		} while (rc == W_ERROR && retry<RETRY);#ifdef PHASE2		/* if retry fails, start from the beginning */		if (rc == W_ERROR && retry==RETRY) 		{			LOG_ERROR_MESSAGE("retry Home interaction failed");			continue;		}		/* if appServer close this socket, reconnect */		if (rc == SOCKET_CLOSE)		{			close(euc.s);			if ((euc.s = _connect(tm_address, *port)) == -1)			{				LOG_ERROR_MESSAGE("re-connect failed");				return;			}			LOG_ERROR_MESSAGE("re-connect");			continue;		}#endif		response_time = time_diff(rt0, rt1);		/* Log the response time and the interaction that was just executed. */		/* log only successful interactions */		pthread_mutex_lock(&mutex_mix_log);		fprintf(log_mix, "%d,%s,%f,%d\n",			time(NULL), interaction_short_name[euc.interaction],			response_time, pthread_self());		fflush(log_mix);		pthread_mutex_unlock(&mutex_mix_log);#ifdef RUNTIME_STATS		pthread_mutex_lock(&mutex_stats[euc.interaction]);		++interaction_count[euc.interaction];		cumulative_response_time[euc.interaction] += response_time;		pthread_mutex_unlock(&mutex_stats[euc.interaction]);#endif /* RUNTIME_STATS */		/* Simulate the user thinking before executing the next interaction. */		think_time.tv_nsec = (long) get_think_time();		think_time.tv_sec = (time_t) (think_time.tv_nsec / 1000);		think_time.tv_nsec = (think_time.tv_nsec % 1000) * 1000000;		while (nanosleep(&think_time, &rem) == -1)		{			if (errno == EINTR)			{				memcpy(&think_time, &rem, sizeof (struct timespec));			}			else			{				LOG_ERROR_MESSAGE("sleep time invalid %d s %ls ns",					think_time.tv_sec, think_time.tv_nsec);				break;			}		}		euc.first_interaction=FALSE;		/*		 * Continue through the interaction mix until this user's duration		 * has expired and this user has completed the Home interaction.		 */		while (usmd > (difftime(time(NULL), user_start) * 1000.0) ||			euc.interaction != HOME)		{ 			euc.previous_interaction = euc.interaction;			euc.interaction = get_next_interaction(euc.interaction);			retry=0;			do			{				/* Get the time before the interaction is executed. */				if (gettimeofday(&rt0, NULL) == -1)				{					perror("gettimeofday");				}				rc = do_interaction(&euc);				/* Get the time after the interaction has executed. */				if (gettimeofday(&rt1, NULL) == -1)				{					perror("gettimeofday");				}				if (rc == W_ERROR)				{					LOG_ERROR_MESSAGE("error executing %s",						interaction_short_name[euc.interaction]);					/* Log the error */					pthread_mutex_lock(&mutex_mix_log);					fprintf(log_mix, "%d,ER,%f,%d\n",						time(NULL), response_time, (double)retry, pthread_self());					fflush(log_mix);					pthread_mutex_unlock(&mutex_mix_log);					dump_interaction_data(&euc);#ifdef PHASE1					/*					 * If an error occurs, reconnect since it could be a					 * dropped connection causing the error.				 	 */					odbc_disconnect(&euc.odbcc);					odbc_connect(&euc.odbcc);#endif /* PHASE1 */					/*					 * If an error occurs, sleep for 10 seconds and try again.					 */					sleep(10);				}				retry++;			} while (rc == W_ERROR && retry < RETRY);#ifdef PHASE2			/* if retry fails, try other interaction or the same                          * interaction with different data */			if (rc == W_ERROR && retry == RETRY) continue;	                /* if appServer close this socket, reconnect */        	        if (rc == SOCKET_CLOSE)			{                        	close(euc.s);                        	if ((euc.s = _connect(tm_address, *port)) == -1)                        	{                               		LOG_ERROR_MESSAGE("re-connect failed");                                	return;                        	}                        	LOG_ERROR_MESSAGE("re-connect");                        	continue;                	}#endif			response_time =				(double) (rt1.tv_sec - rt0.tv_sec) + (double) (rt1.tv_usec - rt0.tv_usec) / 1000000.0;			/*			 * Log the response time and the interaction that was just			 * executed.			 */			pthread_mutex_lock(&mutex_mix_log);			fprintf(log_mix, "%d,%s,%f,%d\n",				time(NULL), interaction_short_name[euc.interaction],				response_time, pthread_self());			fflush(log_mix);			pthread_mutex_unlock(&mutex_mix_log);#ifdef RUNTIME_STATS			pthread_mutex_lock(&mutex_stats[euc.interaction]);			++interaction_count[euc.interaction];			cumulative_response_time[euc.interaction] += response_time;			pthread_mutex_unlock(&mutex_stats[euc.interaction]);#endif /* RUNTIME_STATS */			think_time.tv_nsec = (long) get_think_time();			think_time.tv_sec = (time_t) (think_time.tv_nsec / 1000);			think_time.tv_nsec = (think_time.tv_nsec % 1000) * 1000000;			while (nanosleep(&think_time, &rem) == -1)			{				if (errno == EINTR)				{					memcpy(&think_time, &rem, sizeof (struct timespec));				}				else				{					LOG_ERROR_MESSAGE("sleep time invalid %d s %ls ns",						think_time.tv_sec, think_time.tv_nsec);					break;				}			}		}		/* user session ends*/#ifdef DEBUG		DEBUGMSG("user c_id %lld, sc_id %lld, usmd %f, user_session ended", euc.c_id, euc.sc_id, usmd);#endif	}	while (time(NULL) < stop_time);	sem_wait(&running_eu_count);}