void isi_run_sync(isi_time_t crun) { size_t i, k; int x; for(i = 0; i < allsync.count; i++) { struct isiNetSync *ns = allsync.table[i]; struct memory64x16 *mem = 0; if(!ns) continue; if(ns->ctl) { /* check cache indexes */ if((ns->ctl & NSY_OBJ) && ( !ns->target.id || !allobj.table[ns->target_index] || allobj.table[ns->target_index]->id != ns->target.id)) { ns->ctl ^= NSY_OBJ; isilog(L_DEBUG, "netsync: invalidated index\n"); } if((ns->ctl & NSY_MEM) && ( !ns->memobj.id || !allobj.table[ns->memobj_index] || allobj.table[ns->memobj_index]->id != ns->memobj.id)) { ns->ctl &= ~(NSY_MEMVALID|NSY_MEM|NSY_SYNCMEM); isilog(L_DEBUG, "netsync: invalidated index\n"); } } if((ns->ctl & NSY_MEM)) { mem = (isiram16)allobj.table[ns->memobj_index]; if(mem->info & ISI_RAMINFO_SCAN) ns->ctl |= NSY_SYNCMEM; } } for(i = 0; i < allsync.count; i++) { struct isiNetSync *ns = allsync.table[i]; struct memory64x16 *mem = 0; struct isiInfo *dev = 0; if(!ns) continue; if(!isi_time_lt(&ns->nrun, &crun)) continue; switch(ns->synctype) { /* update indexes */ case ISIN_SYNC_MEM: case ISIN_SYNC_MEMDEV: if(!(ns->ctl & NSY_MEM)) { x = isi_find_obj_index(&ns->memobj); if(x < 0) break; ns->memobj_index = x; ns->ctl |= NSY_MEM; isilog(L_DEBUG, "netsync: adding mem index %x\n", ns->ctl); } if((ns->ctl & NSY_MEM)) { mem = (isiram16)allobj.table[ns->memobj_index]; if(mem->info & ISI_RAMINFO_SCAN) mem->info ^= ISI_RAMINFO_SCAN; } if(mem && !(ns->ctl & NSY_MEMVALID)) { uint32_t mask = 0xffff; uint32_t addr; uint32_t alen; int ex, z; uint32_t idx; for(ex = ns->extents; ex--; ) { addr = ns->base[ex]; alen = ns->len[ex]; for(z = 0; z < alen; z++) { idx = (addr+z) & mask; if(idx > 0x10000) { isilog(L_ERR, "sync: over clear\n"); } mem->ctl[idx] &= 0xffff0000; mem->ctl[idx] |= (ISI_RAMCTL_DELTA|ISI_RAMCTL_SYNC) | ((~mem->ram[idx]) & 0xffff); } } mem->info |= ISI_RAMINFO_SCAN; ns->ctl |= NSY_MEMVALID; } if(ns->synctype != ISIN_SYNC_MEMDEV) break; case ISIN_SYNC_DEVR: case ISIN_SYNC_DEVV: case ISIN_SYNC_DEVRV: if(!(ns->ctl & NSY_OBJ)) { x = isi_find_obj_index(&ns->target); if(x < 0) break; ns->target_index = x; ns->ctl |= NSY_OBJ; isilog(L_DEBUG, "netsync: adding dev index %x\n", ns->ctl); } if((ns->ctl & NSY_OBJ)) dev = (struct isiInfo *)allobj.table[ns->target_index]; break; } switch(ns->synctype) { case ISIN_SYNC_MEM: case ISIN_SYNC_MEMDEV: if((ns->ctl & NSY_MEMVALID) && (ns->ctl & NSY_SYNCMEM)) { uint32_t mask = 0xffff; uint32_t addr; uint32_t alen; uint32_t idx; int ex, z; uint32_t sta = 0; uint32_t sln = 0; uint32_t ndln = 0; int fsync = 1; for(ex = ns->extents; ex--; ) { addr = ns->base[ex]; alen = ns->len[ex]; sta = 0; sln = 0; ndln = 0; *(uint32_t*)(allsync.out+4) = mem->id.id; uint8_t *wlo = allsync.out+8; uint16_t *mw = (uint16_t*)(wlo); uint8_t *wlimit = allsync.out+1294; for(z = 0; z < alen; z++) { idx = (addr+z) & mask; if(sln) { sln+=2; *mw = mem->ram[idx] & 0xffff; mw++; } if(((mem->ram[idx] & 0xffff) ^ (mem->ctl[idx] & 0xffff))) { if(!sln) { sta = idx << 1; sln = 2; mw = (uint16_t*)(wlo+6); *mw = mem->ram[idx] & 0xffff; mw++; } ndln = 0; mem->ctl[idx] &= 0xfffe0000; mem->ctl[idx] |= (mem->ram[idx] & 0xffffu); } else { if(sln) ndln+=2; } if(((uint8_t*)mw) >= wlimit || ndln > 12 || sln >= 1200) { wlo[0] = (uint8_t)(sta); wlo[1] = (uint8_t)(sta>>8); wlo[2] = (uint8_t)(sta>>16); wlo[3] = (uint8_t)(sta>>24); wlo[4] = (uint8_t)(sln); wlo[5] = (uint8_t)(sln >> 8); wlo = (uint8_t*)mw; ndln = sln = sta = 0; if(((uint8_t*)mw) >= wlimit) { fsync = 0; break; } } } if(sln) { wlo[0] = (uint8_t)(sta); wlo[1] = (uint8_t)(sta>>8); wlo[2] = (uint8_t)(sta>>16); wlo[3] = (uint8_t)(sta>>24); wlo[4] = (uint8_t)(sln); wlo[5] = (uint8_t)(sln >> 8); } if((uint8_t*)mw > allsync.out + 8) { *(uint32_t*)(allsync.out) = ISIMSG(SYNCMEM32, 0, ((uint8_t*)mw - (allsync.out + 4))); for(k = 0; k < allses.count; k++) { struct isiSession *ses; ses = allses.table[k]; if(!ses) continue; session_write_msgex(ses, allsync.out); } } } if(fsync) { ns->ctl &= ~NSY_SYNCMEM; } } case ISIN_SYNC_DEVR: case ISIN_SYNC_DEVV: case ISIN_SYNC_DEVRV: if((ns->ctl & NSY_OBJ) && !(ns->ctl & NSY_SYNCOBJ)) { ns->ctl |= NSY_SYNCOBJ; struct isiReflection const *rfl; if(dev->rvproto) { rfl = dev->rvproto; *(uint32_t*)(allsync.out+4) = dev->id.id; if(rfl->length > 1300) { isilog(L_ERR, "sync: over write rv\n"); } memcpy(allsync.out+8, dev->rvstate, rfl->length); *(uint32_t*)(allsync.out) = ISIMSG(SYNCRVS, 0, 4+(rfl->length)); for(k = 0; k < allses.count; k++) { struct isiSession *ses; ses = allses.table[k]; if(!ses) continue; session_write_msgex(ses, allsync.out); } } if(dev->svproto) { rfl = dev->svproto; *(uint32_t*)(allsync.out+4) = dev->id.id; if(rfl->length > 1300) { isilog(L_ERR, "sync: over write sv\n"); } memcpy(allsync.out+8, dev->svstate, rfl->length); *(uint32_t*)(allsync.out) = ISIMSG(SYNCSVS, 0, 4+(rfl->length)); for(k = 0; k < allses.count; k++) { struct isiSession *ses; ses = allses.table[k]; if(!ses) continue; session_write_msgex(ses, allsync.out); } } } break; }
int main(int argc, char**argv, char**envp) { uint32_t cux; uintptr_t gccq = 0; uintptr_t lucycles = 0; uintptr_t lucpus = 0; struct stats sts = {0, }; int paddlimit = 0; int premlimit = 0; isi_init_contable(); isi_register_objects(); isi_objtable_init(); isi_init_sestable(); isi_inittable(&alldev); isi_inittable(&allcpu); isi_synctable_init(); int i; uint32_t k; if( argc > 1 ) { i = parse_args(argc, argv); if(i) return i; } else { fprintf(stderr, gsc_usage, argv[0], argv[0]); return 0; } if(endf) { unsigned char * mflip; uint32_t rsize; loadbinfile(endf, 1, &mflip, &rsize); savebinfile(endf, 0, mflip, rsize); return 0; } struct sigaction hnler; hnler.sa_handler = sysfaulthdl; hnler.sa_flags = 0; if(redisaddr) { redis_make_session_lu(redisaddr); } if(!rqrun && !flagsvr) { fprintf(stderr, "At least -r or -s must be specified.\n"); return 0; } if(flagsvr) { if(!rqrun) enter_service(); makeserver(listenportnumber); } if(rqrun) { make_interactive(); isi_addcpu(); } sigaction(SIGINT, &hnler, NULL); sigaction(SIGTERM, &hnler, NULL); sigaction(SIGHUP, &hnler, NULL); sigaction(SIGPIPE, &hnler, NULL); fetchtime(<UTime); lucycles = 0; // how many cycles ran (debugging) cux = 0; // CPU index - currently never changes if(rqrun && allcpu.count && ((struct isiCPUInfo*)allcpu.table[cux])->ctl & ISICTL_DEBUG) { showdiag_dcpu(allcpu.table[cux], 1); } while(!haltnow) { struct isiCPUInfo * ccpu; struct isiInfo * ccpi; struct timespec CRun; ccpu = (struct isiCPUInfo*)(ccpi = allcpu.table[cux]); fetchtime(&CRun); if(!allcpu.count) { struct timespec stime = {0, 10000}; nanosleep(&stime, NULL); } else { int ccq = 0; int tcc = numberofcpus * 2; if(tcc < 20) tcc = 20; while(ccq < tcc && isi_time_lt(&ccpi->nrun, &CRun)) { sts.quanta++; ccpi->c->RunCycles(ccpi, CRun); //TODO some hardware may need to work at the same time lucycles += ccpu->cycl; if(rqrun && (ccpu->ctl & ISICTL_TRACE) && (ccpu->cycl)) { showdiag_dcpu(ccpi, 1); } ccpu->cycl = 0; fetchtime(&CRun); ccq++; } if(ccq >= tcc) gccq++; sts.cpusched++; fetchtime(&CRun); if(ccpi->updev.t && ccpi->updev.t->c->RunCycles) { ccpi->updev.t->c->RunCycles(ccpi->updev.t, CRun); } } fetchtime(&CRun); isi_run_sync(CRun); fetchtime(&CRun); if(CRun.tv_sec > LTUTime.tv_sec) { // roughly one second between status output if(rqrun && !flagdbg) { // interactive diag double clkdelta; float clkrate; if(allcpu.count) showdiag_dcpu(allcpu.table[0], 0); clkdelta = ((double)(CRun.tv_sec - LTUTime.tv_sec)) + (((double)CRun.tv_nsec) * 0.000000001); clkdelta-=(((double)LTUTime.tv_nsec) * 0.000000001); if(!lucpus) lucpus = 1; clkrate = ((((double)lucycles) * clkdelta) * 0.001) / numberofcpus; fprintf(stderr, "DC: %.4f sec, %d at % 9.3f kHz (% 8ld) [Q:% 8d, S:% 8d, SC:% 8d]\r", clkdelta, numberofcpus, clkrate, gccq, sts.quanta, sts.cpusched, sts.cpusched / numberofcpus ); if(allcpu.count) showdiag_up(4); } fetchtime(<UTime); if(gccq >= sts.cpusched / numberofcpus ) { if(numberofcpus > softcpumin) { numberofcpus--; if(rqrun) fprintf(stderr, "TODO: Offline a CPU\n"); premlimit--; paddlimit = 0; } } else { if(numberofcpus < softcpumax) { //fetchtime(&allcpus[numberofcpus].nrun); //isi_addtime(&allcpus[numberofcpus].nrun, quantum); numberofcpus++; if(rqrun) fprintf(stderr, "TODO: Online a CPU\n"); } } lucycles = 0; lucpus = 0; gccq = 0; memset(&sts, 0, sizeof(struct stats)); if(premlimit < 20) premlimit+=10; if(paddlimit < 20) paddlimit+=2; for(k = 0; k < allses.count; k++) { struct isiSession *ses = allses.table[k]; if(ses->LTick) ses->LTick(ses, CRun); } } if(allses.pcount != allses.count) { if(allses.ptable) { free(allses.ptable); allses.ptable = 0; } allses.pcount = allses.count; allses.ptable = (struct pollfd*)isi_alloc(sizeof(struct pollfd) * allses.pcount); if(!allses.ptable) { isilogerr("malloc poll table fails!"); } i = 0; for(k = 0; k < allses.count; k++) { allses.ptable[i].fd = allses.table[k]->sfd; allses.ptable[i].events = POLLIN; i++; } } if(allses.ptable) { i = poll(allses.ptable, allses.pcount, 0); } else { i = 0; } for(k = 0; k < allses.count; k++) { struct isiSession *ses = allses.table[k]; if(ses && ses->STick && (ses->cmdqstart != ses->cmdqend)) ses->STick(ses, CRun); } if(i > 0) { for(k = 0; k < allses.pcount; k++) { if(!allses.ptable[k].revents) continue; struct isiSession *ses = allses.table[k]; const char *etxt = 0; /* Here be dragons */ switch(allses.ptable[k].revents) { case POLLERR: etxt = "poll: FD error\n"; goto sessionerror; case POLLHUP: etxt = "poll: FD hangup\n"; goto sessionerror; case POLLNVAL: etxt = "poll: FD invalid\n"; goto sessionerror; default: if(allses.ptable[k].revents & POLLIN) { if(ses->sfd == allses.ptable[k].fd) { if(ses->Recv(ses, CRun)) goto sessionerror; } else { isilog(L_ERR, "netses: session ID error\n"); } } } continue; sessionerror: if(etxt) isilog(L_ERR, etxt); if(ses->sfd == allses.ptable[k].fd) { isi_delete_ses(ses); k = allses.pcount; } } } if(!flagdbg) { cux++; if(!(cux < allcpu.count)) { cux = 0; } } else { numberofcpus = 1; cux = 0; } if(haltnow) { break; } } if(flagsvr) { isilog(L_WARN, "closing connections\n"); while(allses.count) { isi_delete_ses(allses.table[0]); } } while(allobj.count) { isi_delete_object(allobj.table[0]); } if(rqrun) printf("\n\n\n\n"); return 0; }