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]--; }
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; }