コード例 #1
0
ファイル: x_call.c プロジェクト: Aj0Ay/dtrace-for-linux
void
dtrace_xcall2(processorid_t cpu, dtrace_xcall_t func, void *arg)
{	int	c;
	int	cpu_id = smp_processor_id();
	int	cpus_todo = 0;
# if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 24)
typedef struct cpumask cpumask_t;
//#define cpu_set(c, mask) cpumask_set_cpu(c, &(mask))
//#define cpus_clear(mask) cpumask_clear(&mask)
# endif
	cpumask_t mask;

	/***********************************************/
	/*   If  we had an internal panic, stop doing  */
	/*   xcalls.   Shouldnt  happen,  but  useful  */
	/*   during debugging so we can diagnose what  */
	/*   caused the panic.			       */
	/***********************************************/
	if (dtrace_shutdown)
		return;
	/***********************************************/
	/*   Special case - just 'us'.		       */
	/***********************************************/
	cnt_xcall1++;
	if (cpu_id == cpu) {
		local_irq_disable();
//dtrace_printf("[%d] sole cnt=%lu\n", smp_processor_id(), cnt_xcall1);
		func(arg);
		local_irq_enable();
		return;
	}

	/***********************************************/
	/*   Set  up  the  cpu  mask  to  do just the  */
	/*   relevant cpu.			       */
	/***********************************************/
	if (cpu != DTRACE_CPUALL) {
//dtrace_printf("just me %d %d\n", cpu_id, cpu);
		cpu = 1 << cpu;
	}


//dtrace_printf("xcall %d f=%p\n", cpu_id, func);
	cnt_xcall2++;
	if (xcall_levels[cpu_id]++)
		cnt_xcall3++;
	/***********************************************/
	/*   Set  up  the  rendezvous  with the other  */
	/*   targetted  cpus.  We use a nearly square  */
	/*   NCPU*NCPU matrix to allow for any cpu to  */
	/*   wait  for  any  other. We have two slots  */
	/*   per  cpu  -  because  we  may  be  in an  */
	/*   interrupt.				       */
	/*   					       */
	/*   The  interrupt  slave  will  service all  */
	/*   queued  calls  -  sometimes  it  will be  */
	/*   lucky and see multiple, especially if we  */
	/*   are heavily loaded.		       */
	/***********************************************/
	cpus_clear(mask);
	for (c = 0; c < nr_cpus; c++) {
		struct xcalls *xc = &xcalls[cpu_id][c];
		unsigned int cnt;

		/***********************************************/
		/*   Dont  set  ourselves  - we dont want our  */
		/*   cpu  to  be  taking an IPI interrupt and  */
		/*   doing   the   work   twice.   We  inline  */
		/*   ourselves below.			       */
		/***********************************************/
		if ((cpu & (1 << c)) == 0 || c == cpu_id) {
			continue;
		}

		/***********************************************/
		/*   Is  this  safe?  We want to avoid an IPI  */
		/*   call  if the other cpu is idle/not doing  */
		/*   dtrace  work.  If  thats the case and we  */
		/*   are  calling  dtrace_sync,  then  we can  */
		/*   avoid the xcall.			       */
		/***********************************************/
		if ((void *) func == (void *) dtrace_sync_func &&
		    cpu_core[c].cpuc_probe_level == 0) {
			cpu &= ~(1 << c);
			cnt_xcall7++;
			continue;
		}
//dtrace_printf("xcall %p\n", func);

		xc->xc_func = func;
		xc->xc_arg = arg;
		/***********************************************/
		/*   Spinlock  in  case  the  interrupt hasnt  */
		/*   fired.  This  should  be  very rare, and  */
		/*   when it happens, we would be hanging for  */
		/*   100m  iterations  (about  1s). We reduce  */
		/*   the   chance  of  a  hit  by  using  the  */
		/*   NCPU*NCPU*2 array approach. These things  */
		/*   happen  when buffers are full or user is  */
		/*   ^C-ing dtrace.			       */
		/***********************************************/
		for (cnt = 0; dtrace_cas32((void *) &xc->xc_state, XC_WORKING, XC_WORKING) == XC_WORKING; cnt++) {
			/***********************************************/
			/*   Avoid noise for tiny windows.	       */
			/***********************************************/
			if ((cnt == 0 && xcall_debug) || !(xcall_debug && cnt == 50)) {
				dtrace_printf("[%d] cpu%d in wrong state (state=%d)\n",
					smp_processor_id(), c, xc->xc_state);
			}
//			xcall_slave2();
			if (cnt == 100 * 1000 * 1000) {
				dtrace_printf("[%d] cpu%d - busting lock\n",
					smp_processor_id(), c);
				break;
			}
		}
		if ((cnt && xcall_debug) || (!xcall_debug && cnt > 50)) {
			dtrace_printf("[%d] cpu%d in wrong state (state=%d) %u cycles\n",
				smp_processor_id(), c, xc->xc_state, cnt);
		}
		/***********************************************/
		/*   As  soon  as  we set xc_state and BEFORE  */
		/*   the  apic  call,  the  cpu  may  see the  */
		/*   change  since  it  may  be taking an IPI  */
		/*   interrupt  for  someone else. We need to  */
		/*   be  careful  with  barriers  (I  think -  */
		/*   although    the   clflush/wmb   may   be  */
		/*   redundant).			       */
		/***********************************************/
		xc->xc_state = XC_WORKING;
//		clflush(&xc->xc_state);
//		smp_wmb();
		cpu_set(c, mask);
		cpus_todo++;
	}

	smp_mb();

	/***********************************************/
	/*   Now tell the other cpus to do some work.  */
	/***********************************************/
	if (cpus_todo)
		send_ipi_interrupt(&mask, ipi_vector);

	/***********************************************/
	/*   Check for ourselves.		       */
	/***********************************************/
	if (cpu & (1 << cpu_id)) {
		func(arg);
	}

	if (xcall_debug)
		dtrace_printf("[%d] getting ready.... (%ld) mask=%x func=%p\n", smp_processor_id(), cnt_xcall1, *(int *) &mask, func);

	/***********************************************/
	/*   Wait for the cpus we invoked the IPI on.  */
	/*   Cycle  thru  the  cpus,  to avoid mutual  */
	/*   deadlock  between one cpu trying to call  */
	/*   us whilst we are calling them.	       */
	/***********************************************/
	while (cpus_todo > 0) {
		for (c = 0; c < nr_cpus && cpus_todo > 0; c++) {
			xcall_slave2();
			if (c == cpu_id || (cpu & (1 << c)) == 0)
				continue;

			/***********************************************/
			/*   Wait  a  little  while  for  this cpu to  */
			/*   respond before going on to the next one.  */
			/***********************************************/
			if (ack_wait(c, 100)) {
				cpus_todo--;
				cpu &= ~(1 << c);
			}
		}
	}
//	smp_mb();

	xcall_levels[cpu_id]--;
}
コード例 #2
0
ファイル: tftp_client.c プロジェクト: ParthShah91/tftpClient
int tftp_send(char* file, int socketFd)
{
	char buf[512]; //TODO remove hardcoding
	uint16_t block_num = 0;
	int i = 0, ret = 0, num_bytes_read = 0, status;
	bool file_read_complete = false;
	FILE* fp;

	printf("tftp_send\n");
	/* Open file which is requested to send */
	fp = fopen(file,"r");
	if(!fp) {
		perror("Couldn't open file for reading\n");
		return ERROR;
	}

	/* Create write request and send it */
	/* Start timer and wait for ack until time out if error packet get then abort transfer */
	/* If time occurs and ack is not there then retransmit write request */
	/* Get tid from ack if first run then store it otherwise compare */
	rw_req_packet(socketFd, WRITE, file, "netascii");
	i = 0;
	while(i++ < RTCOUNT)
	{
		ret = ack_wait(socketFd, file);
		if (ret == -2) {
			rw_req_packet(socketFd, WRITE, file, "netascii");
		}
		else if(ret == -1)
		{
			fclose(fp);
			return -1;
		}
		else
			break;

	}

	/* Read data from file and create data packet with block number. send data packet */
	/* Start timer and wait for ack until timeout. no ack then retransmit packet */
	while(!file_read_complete)
	{
		num_bytes_read = fread(buf, 1, 512, fp);
		if(!num_bytes_read)
		{
			if(ferror(fp))
			{
				perror("file read");
				return -1;
			}
		}
		//printf("++ blockNum: %d\n", block_num);
		status = send_data(socketFd, buf, block_num, num_bytes_read);
		if(status < 0)
		{
			fclose(fp);
			break;	
		}
		else if (status > 0)
		{
			//TODO ack_wait(socketFd, file);
			ret = ack_wait(socketFd, file);
			fclose(fp);
			printf("sent successfully");
			break;	
			
		}
		i = 0;
		while(i++ < RTCOUNT)
		{
			ret = ack_wait(socketFd, file);
			if (ret == -1)
			{
				printf("Sending data again for block_num %d..\n", block_num);
				send_data(socketFd, buf, block_num, num_bytes_read);
			}
			/*else if(ret == -1) //TODO
			{
				fclose(fp);
				return -1;
			}*/
			else
			{
				//fclose(fp);
				break;
			}

		}
		block_num++;
		//printf("\n\n");
		//file_read_complete = true; //TODO update this condition
	}
	return 0;
}