void vegas_sdfits_thread(void *_args) {
    
    /* Get args */
    struct vegas_thread_args *args = (struct vegas_thread_args *)_args;
    pthread_cleanup_push((void *)vegas_thread_set_finished, args);
    
    /* Set cpu affinity */
    int rv = sched_setaffinity(0, sizeof(cpu_set_t), &args->cpuset);
    if (rv<0) { 
        vegas_error("vegas_sdfits_thread", "Error setting cpu affinity.");
        perror("sched_setaffinity");
    }

    /* Set priority */
    rv=0;
    if (args->priority != 0)
    {
        struct sched_param priority_param;
        priority_param.sched_priority = args->priority;
        rv = pthread_setschedparam(pthread_self(), SCHED_FIFO, &priority_param);
    }
    if (rv<0) {
        vegas_error("vegas_sdfits_thread", "Error setting priority level.");
        perror("set_priority");
    }
    
    /* Attach to status shared mem area */
    struct vegas_status st;
    rv = vegas_status_attach(&st);
    if (rv!=VEGAS_OK) {
        vegas_error("vegas_sdfits_thread", 
                    "Error attaching to status shared memory.");
        pthread_exit(NULL);
    }
    pthread_cleanup_push((void *)vegas_status_detach, &st);
    pthread_cleanup_push((void *)set_exit_status, &st);
    
    /* Init status */
    vegas_status_lock_safe(&st);
    hputs(st.buf, STATUS_KEY, "init");
    vegas_status_unlock_safe(&st);
    
    /* Initialize some key parameters */
    struct vegas_params gp;
    struct sdfits sf;
    sf.data_columns.data = NULL;
    sf.filenum = 0;
    sf.new_file = 1; // This is crucial
    pthread_cleanup_push((void *)vegas_free_sdfits, &sf);
    pthread_cleanup_push((void *)sdfits_close, &sf);
    //pf.multifile = 0;  // Use a single file for fold mode
    sf.multifile = 1;  // Use a multiple files for fold mode
    sf.quiet = 0;      // Print a message per each subint written
    
    /* Attach to databuf shared mem */
    struct vegas_databuf *db;
    db = vegas_databuf_attach(args->input_buffer);
    if (db==NULL) {
        vegas_error("vegas_sdfits_thread",
                    "Error attaching to databuf shared memory.");
        pthread_exit(NULL);
    }
    pthread_cleanup_push((void *)vegas_databuf_detach, db);
    
    /* Loop */
    int curblock=0, total_status=0, firsttime=1, run=1, got_packet_0=0, dataset=0;
    char *ptr;
    char tmpstr[256];
    int scan_finished=0, old_filenum;
    int num_exposures_written = 0;
    int old_integ_num = -1;

    signal(SIGINT, cc);
    do {
        /* Note waiting status */
        vegas_status_lock_safe(&st);
        if (got_packet_0)
            sprintf(tmpstr, "waiting(%d)", curblock);
        else
            sprintf(tmpstr, "ready");
        hputs(st.buf, STATUS_KEY, tmpstr);
        vegas_status_unlock_safe(&st);
        
        /* Wait for buf to have data */
        rv = vegas_databuf_wait_filled(db, curblock);
        if (rv!=0) {
            // This is a big ol' kludge to avoid this process hanging
            // due to thread synchronization problems.
            sleep(1);
            continue; 
        }

        /* Note current block */
        vegas_status_lock_safe(&st);
        hputi4(st.buf, "DSKBLKIN", curblock);
        vegas_status_unlock_safe(&st);

        /* See how full databuf is */
        total_status = vegas_databuf_total_status(db);
        
        /* Read param structs for this block */
        ptr = vegas_databuf_header(db, curblock);
        if (firsttime) {
            vegas_read_obs_params(ptr, &gp, &sf);
            firsttime = 0;
        } else {
            vegas_read_subint_params(ptr, &gp, &sf);
        }

        /* Note waiting status */
        vegas_status_lock_safe(&st);
        hputs(st.buf, STATUS_KEY, "writing");
        vegas_status_unlock_safe(&st);

        struct sdfits_data_columns* data_cols;
        struct databuf_index* db_index;

        db_index = (struct databuf_index*)(vegas_databuf_index(db, curblock));

        /* Read the block index, writing each dataset to a SDFITS file */
        for(dataset = 0; dataset < db_index->num_datasets; dataset++)
        {
            data_cols = (struct sdfits_data_columns*)(vegas_databuf_data(db, curblock) +
                        db_index->disk_buf[dataset].struct_offset);

            sf.data_columns = *data_cols;

            /* Write the data */
            old_filenum = sf.filenum;
            sdfits_write_subint(&sf);

            /*Write new file number to shared memory*/
            if(sf.filenum != old_filenum)
            {
                vegas_status_lock_safe(&st);
                hputi4(st.buf, "FILENUM", sf.filenum);
                vegas_status_unlock_safe(&st);
            }

            /* If a new integration number, increment the number of exposures written */
            if(data_cols->integ_num != old_integ_num)
            {
                num_exposures_written += 1;
                old_integ_num = data_cols->integ_num;
            }

        }

        /* Indicate number of exposures written */
        vegas_status_lock_safe(&st);
        hputi4(st.buf, "DSKEXPWR", num_exposures_written);
        vegas_status_unlock_safe(&st);

        /* For debugging... */
        if (gp.drop_frac > 0.0) {
            printf("Block %d dropped %.3g%% of the packets\n", 
                    sf.tot_rows, gp.drop_frac*100.0);
        }

        /* Mark as free */
        vegas_databuf_set_free(db, curblock);
        
        /* Go to next block */
        curblock = (curblock + 1) % db->n_block;
        
        /* Check for cancel */
        pthread_testcancel();
        
    } while (run && !scan_finished);
    
    /* Cleanup */
    pthread_exit(NULL);
    
    pthread_cleanup_pop(0); /* Closes sdfits_close */
    pthread_cleanup_pop(0); /* Closes vegas_free_sdfits */
    pthread_cleanup_pop(0); /* Closes set_exit_status */
    pthread_cleanup_pop(0); /* Closes set_finished */
    pthread_cleanup_pop(0); /* Closes vegas_status_detach */
    pthread_cleanup_pop(0); /* Closes vegas_databuf_detach */
}
int main(int argc, char *argv[]) {

    int rv;
    struct vegas_status s;

    rv = vegas_status_attach(&s);
    if (rv!=VEGAS_OK) {
        fprintf(stderr, "Error connecting to shared mem.\n");
        perror(NULL);
        exit(1);
    }

    vegas_status_lock(&s);

    /* Loop over cmd line to fill in params */
    static struct option long_opts[] = {
        {"key",    1, NULL, 'k'},
        {"get",    1, NULL, 'g'},
        {"string", 1, NULL, 's'},
        {"float",  1, NULL, 'f'},
        {"double", 1, NULL, 'd'},
        {"int",    1, NULL, 'i'},
        {"quiet",  0, NULL, 'q'},
        {"clear",  0, NULL, 'C'},
        {"del",    0, NULL, 'D'},
        {0,0,0,0}
    };
    int opt,opti;
    char *key=NULL;
    float flttmp;
    double dbltmp;
    int inttmp;
    int quiet=0, clear=0;
    while ((opt=getopt_long(argc,argv,"k:g:s:f:d:i:qCD",long_opts,&opti))!=-1) {
        switch (opt) {
            case 'k':
                key = optarg;
                break;
            case 'g':
                hgetr8(s.buf, optarg, &dbltmp);
                printf("%g\n", dbltmp);
                break;
            case 's':
                if (key) 
                    hputs(s.buf, key, optarg);
                break;
            case 'f':
                flttmp = atof(optarg);
                if (key) 
                    hputr4(s.buf, key, flttmp);
                break;
            case 'd':
                dbltmp = atof(optarg);
                if (key) 
                    hputr8(s.buf, key, dbltmp);
                break;
            case 'i':
                inttmp = atoi(optarg);
                if (key) 
                    hputi4(s.buf, key, inttmp);
                break;
            case 'D':
                if (key)
                    hdel(s.buf, key);
                break;
            case 'C':
                clear=1;
                break;
            case 'q':
                quiet=1;
                break;
            default:
                break;
        }
    }

    /* If not quiet, print out buffer */
    if (!quiet) { 
        printf(s.buf); printf("\n"); 
    }

    vegas_status_unlock(&s);

    if (clear) 
        vegas_status_clear(&s);

    exit(0);
}
Exemple #3
0
int main(int argc, char *argv[]) {

    static struct option long_opts[] = {
        {"help",   0, NULL, 'h'},
        {0,0,0,0}
    };
    int opt, opti;
    while ((opt=getopt_long(argc,argv,"h",long_opts,&opti))!=-1) {
        switch (opt) {
        default:
        case 'h':
            usage();
            exit(0);
            break;
        }
    }

    /* Create FIFO */
    int rv = mkfifo(vegas_DAQ_CONTROL, 0666);
    if (rv!=0 && errno!=EEXIST) {
        fprintf(stderr, "vegas_daq_server: Error creating control fifo\n");
        perror("mkfifo");
        exit(1);
    }

    /* Open command FIFO for read */
#define MAX_CMD_LEN 1024
    char cmd[MAX_CMD_LEN];
    int command_fifo;
    command_fifo = open(vegas_DAQ_CONTROL, O_RDONLY | O_NONBLOCK);
    if (command_fifo<0) {
        fprintf(stderr, "vegas_daq_server: Error opening control fifo\n");
        perror("open");
        exit(1);
    }

    /* Attach to shared memory buffers */
    struct vegas_status stat;
    struct vegas_databuf *dbuf_net=NULL, *dbuf_pfb=NULL, *dbuf_acc=NULL;
    rv = vegas_status_attach(&stat);
    const int netbuf_id = 1;
    const int pfbbuf_id = 2;
    const int accbuf_id = 3;
    if (rv!=VEGAS_OK) {
        fprintf(stderr, "Error connecting to vegas_status\n");
        exit(1);
    }
    dbuf_net = vegas_databuf_attach(netbuf_id);
    if (dbuf_net==NULL) {
        fprintf(stderr, "Error connecting to vegas_databuf (raw net)\n");
        exit(1);
    }
    vegas_databuf_clear(dbuf_net);
    dbuf_pfb = vegas_databuf_attach(pfbbuf_id);
    if (dbuf_pfb==NULL) {
        fprintf(stderr, "Error connecting to vegas_databuf (accum input)\n");
        exit(1);
    }
    vegas_databuf_clear(dbuf_pfb);

    dbuf_acc = vegas_databuf_attach(accbuf_id);
    if (dbuf_acc==NULL) {
        fprintf(stderr, "Error connecting to vegas_databuf (accum output)\n");
        exit(1);
    }
    vegas_databuf_clear(dbuf_acc);

    /* Thread setup */
#define MAX_THREAD 8
    int i;
    int nthread_cur = 0;
    struct vegas_thread_args args[MAX_THREAD];
    pthread_t thread_id[MAX_THREAD];
    for (i=0; i<MAX_THREAD; i++) thread_id[i] = 0;

    /* Print start time for logs */
    time_t curtime = time(NULL);
    char tmp[256];
    printf("\nvegas_daq_server started at %s", ctime_r(&curtime,tmp));
    fflush(stdout);

    /* hmm.. keep this old signal stuff?? */
    run=1;
    srv_run=1;
    signal(SIGINT, srv_cc);
    signal(SIGTERM, srv_quit);

    /* Loop over recv'd commands, process them */
    int cmd_wait=1;
    while (cmd_wait && srv_run) {

        // Check to see if threads have exited, if so, stop them
        if (check_thread_exit(args, nthread_cur)) {
            run = 0;
            stop_threads(args, thread_id, nthread_cur);
            nthread_cur = 0;
        }

        // Heartbeat, status update
        time_t curtime;
        char timestr[32];
        char *ctmp;
        time(&curtime);
        ctime_r(&curtime, timestr);
        ctmp = strchr(timestr, '\n');
        if (ctmp!=NULL) {
            *ctmp = '\0';
        }
        else {
            timestr[0]='\0';
        }
        vegas_status_lock(&stat);
        hputs(stat.buf, "DAQPULSE", timestr);
        hputs(stat.buf, "DAQSTATE", nthread_cur==0 ? "stopped" : "running");
        vegas_status_unlock(&stat);

        // Flush any status/error/etc for logfiles
        fflush(stdout);
        fflush(stderr);

        // Wait for data on fifo
        struct pollfd pfd;
        pfd.fd = command_fifo;
        pfd.events = POLLIN;
        rv = poll(&pfd, 1, 1000);
        if (rv==0) {
            continue;
        }
        else if (rv<0) {
            if (errno!=EINTR) perror("poll");
            continue;
        }

        // If we got POLLHUP, it means the other side closed its
        // connection.  Close and reopen the FIFO to clear this
        // condition.  Is there a better/recommended way to do this?
        if (pfd.revents==POLLHUP) {
            close(command_fifo);
            command_fifo = open(vegas_DAQ_CONTROL, O_RDONLY | O_NONBLOCK);
            if (command_fifo<0) {
                fprintf(stderr,
                        "vegas_daq_server: Error opening control fifo\n");
                perror("open");
                break;
            }
            continue;
        }

        // Read the command
        memset(cmd, 0, MAX_CMD_LEN);
        rv = read(command_fifo, cmd, MAX_CMD_LEN-1);
        if (rv==0) {
            continue;
        }
        else if (rv<0) {
            if (errno==EAGAIN) {
                continue;
            }
            else {
                perror("read");
                continue;
            }
        }

        // Truncate at newline
        // TODO: allow multiple commands in one read?
        char *ptr = strchr(cmd, '\n');
        if (ptr!=NULL) *ptr='\0';

        // Process the command
        if (strncasecmp(cmd,"QUIT",MAX_CMD_LEN)==0) {
            // Exit program
            printf("Exit\n");
            run = 0;
            stop_threads(args, thread_id, nthread_cur);
            cmd_wait=0;
            continue;
        }

        else if (strncasecmp(cmd,"START",MAX_CMD_LEN)==0 ||
                 strncasecmp(cmd,"MONITOR",MAX_CMD_LEN)==0) {
            // Start observations
            // TODO : decide how to behave if observations are running
            printf("Start observations\n");

            if (nthread_cur>0) {
                printf("  observations already running!\n");
            } else {

                // Figure out which mode to start
                char obs_mode[32];
                if (strncasecmp(cmd,"START",MAX_CMD_LEN)==0) {
                    vegas_status_lock(&stat);
                    vegas_read_obs_mode(stat.buf, obs_mode);
                    vegas_status_unlock(&stat);
                } else {
                    strncpy(obs_mode, cmd, 32);
                }
                printf("  obs_mode = %s\n", obs_mode);

                // Clear out data bufs
                vegas_databuf_clear(dbuf_net);
                vegas_databuf_clear(dbuf_pfb);
                vegas_databuf_clear(dbuf_acc);


                // Do it
                run = 1;
                if (strncasecmp(obs_mode, "HBW", 4)==0) {
                    hputs(stat.buf, "BW_MODE", "high");
                    hputs(stat.buf, "SWVER", "1.4");
                    init_hbw_mode(args, &nthread_cur);
                    start_hbw_mode(args, thread_id);
                } else if (strncasecmp(obs_mode, "LBW", 4)==0) {
                    hputs(stat.buf, "BW_MODE", "low");
                    hputs(stat.buf, "SWVER", "1.4");

                    init_lbw_mode(args, &nthread_cur);
                    start_lbw_mode(args, thread_id);
                } else if (strncasecmp(obs_mode, "MONITOR", 8)==0) {
                    init_monitor_mode(args, &nthread_cur);
                    start_monitor_mode(args, thread_id);
                } else {
                    printf("  unrecognized obs_mode!\n");
                }

            }

        }

        else if (strncasecmp(cmd,"STOP",MAX_CMD_LEN)==0) {
            // Stop observations
            printf("Stop observations\n");
            run = 0;
            stop_threads(args, thread_id, nthread_cur);
            nthread_cur = 0;
        }

        else {
            // Unknown command
            printf("Unrecognized command '%s'\n", cmd);
        }
    }

    /* Stop any running threads */
    run = 0;
    stop_threads(args, thread_id, nthread_cur);

    if (command_fifo>0) close(command_fifo);

    vegas_status_lock(&stat);
    hputs(stat.buf, "DAQSTATE", "exiting");
    vegas_status_unlock(&stat);

    curtime = time(NULL);
    printf("vegas_daq_server exiting cleanly at %s\n", ctime_r(&curtime,tmp));

    fflush(stdout);
    fflush(stderr);

    /* TODO: remove FIFO */

    exit(0);
}
/* This thread is passed a single arg, pointer
 * to the vegas_udp_params struct.  This thread should 
 * be cancelled and restarted if any hardware params
 * change, as this potentially affects packet size, etc.
 */
void *vegas_net_thread(void *_args) {

    /* Get arguments */
    struct vegas_thread_args *args = (struct vegas_thread_args *)_args;
    int rv;

    /* Set cpu affinity */
    cpu_set_t cpuset, cpuset_orig;
    sched_getaffinity(0, sizeof(cpu_set_t), &cpuset_orig);
    //CPU_ZERO(&cpuset);
    CPU_SET(13, &cpuset);
    rv = sched_setaffinity(0, sizeof(cpu_set_t), &cpuset);
    if (rv<0) { 
        vegas_error("vegas_net_thread", "Error setting cpu affinity.");
        perror("sched_setaffinity");
    }

    /* Set priority */
    rv = setpriority(PRIO_PROCESS, 0, args->priority);
    if (rv<0) {
        vegas_error("vegas_net_thread", "Error setting priority level.");
        perror("set_priority");
    }

    /* Attach to status shared mem area */
    struct vegas_status st;
    rv = vegas_status_attach(&st);
    if (rv!=VEGAS_OK) {
        vegas_error("vegas_net_thread", 
                "Error attaching to status shared memory.");
        pthread_exit(NULL);
    }
    pthread_cleanup_push((void *)vegas_status_detach, &st);
    pthread_cleanup_push((void *)set_exit_status, &st);

    /* Init status, read info */
    vegas_status_lock_safe(&st);
    hputs(st.buf, STATUS_KEY, "init");
    vegas_status_unlock_safe(&st);

    /* Read in general parameters */
    struct vegas_params gp;
    struct sdfits pf;
    char status_buf[VEGAS_STATUS_SIZE];
    vegas_status_lock_safe(&st);
    memcpy(status_buf, st.buf, VEGAS_STATUS_SIZE);
    vegas_status_unlock_safe(&st);
    vegas_read_obs_params(status_buf, &gp, &pf);
    pthread_cleanup_push((void *)vegas_free_sdfits, &pf);

    /* Read network params */
    struct vegas_udp_params up;
    vegas_read_net_params(status_buf, &up);

    /* Attach to databuf shared mem */
    struct vegas_databuf *db;
    db = vegas_databuf_attach(args->output_buffer); 
    if (db==NULL) {
        vegas_error("vegas_net_thread",
                "Error attaching to databuf shared memory.");
        pthread_exit(NULL);
    }
    pthread_cleanup_push((void *)vegas_databuf_detach, db);

    /* Time parameters */
    double meas_stt_mjd=0.0;
    double meas_stt_offs=0.0;

    /* See which packet format to use */
    int nchan=0, npol=0;
    nchan = pf.hdr.nchan;
    npol = pf.hdr.npol;

    /* Figure out size of data in each packet, number of packets
     * per block, etc.  Changing packet size during an obs is not
     * recommended.
     */
    int block_size;
    struct vegas_udp_packet p;
    size_t heap_size, spead_hdr_size;
    unsigned int heaps_per_block, packets_per_heap; 
    char bw_mode[16];

    if (hgets(status_buf, "BW_MODE", 16, bw_mode))
    {
        if(strncmp(bw_mode, "high", 4) == 0)
        {
            heap_size = sizeof(struct freq_spead_heap) + nchan*4*sizeof(int);
            spead_hdr_size = sizeof(struct freq_spead_heap);
            packets_per_heap = nchan*4*sizeof(int) / PAYLOAD_SIZE;
        }
        else if(strncmp(bw_mode, "low", 3) == 0)
        {
            heap_size = sizeof(struct time_spead_heap) + PAYLOAD_SIZE;
            spead_hdr_size = sizeof(struct time_spead_heap);
            packets_per_heap = 1;
        }
        else
            vegas_error("vegas_net_thread", "Unsupported bandwidth mode");
    }
    else
        vegas_error("vegas_net_thread", "BW_MODE not set");

    if (hgeti4(status_buf, "BLOCSIZE", &block_size)==0) {
            block_size = db->block_size;
            hputi4(status_buf, "BLOCSIZE", block_size);
    } else {
        if (block_size > db->block_size) {
            vegas_error("vegas_net_thread", "BLOCSIZE > databuf block_size");
            block_size = db->block_size;
            hputi4(status_buf, "BLOCSIZE", block_size);
        }
    }
    heaps_per_block =   (block_size - MAX_HEAPS_PER_BLK*spead_hdr_size) /
                        (heap_size - spead_hdr_size);

    /* List of databuf blocks currently in use */
    unsigned i;
    const int nblock = 2;
    struct datablock_stats blocks[nblock];
    for (i=0; i<nblock; i++) 
        init_block(&blocks[i], db, heap_size, spead_hdr_size, heaps_per_block);

    /* Convenience names for first/last blocks in set */
    struct datablock_stats *fblock, *lblock;
    fblock = &blocks[0];
    lblock = &blocks[nblock-1];

    /* Misc counters, etc */
    char *curdata=NULL, *curheader=NULL, *curindex=NULL;
    unsigned int heap_cntr=0, last_heap_cntr=2048, nextblock_heap_cntr=0;
    unsigned int heap_offset;
    unsigned int seq_num=0, last_seq_num=1050;
    int heap_cntr_diff, seq_num_diff;
    unsigned int obs_started = 0;
    unsigned long long npacket_total, npacket_this_block=0, ndropped_total;
    double drop_frac_avg=0.0;
    const double drop_lpf = 0.25;
    prev_heap_cntr = 0;
    prev_heap_offset = 0;
    char msg[256];

    /* Give all the threads a chance to start before opening network socket */
    sleep(1);

    /* Set up UDP socket */
    rv = vegas_udp_init(&up);
    if (rv!=VEGAS_OK) {
        vegas_error("vegas_net_thread",
                "Error opening UDP socket.");
        pthread_exit(NULL);
    }
    pthread_cleanup_push((void *)vegas_udp_close, &up);

    /* Main loop */
    unsigned force_new_block=0, waiting=-1;
    signal(SIGINT,cc);
    while (run) {

        /* Wait for data */
        rv = vegas_udp_wait(&up);
        if (rv!=VEGAS_OK) {
            if (rv==VEGAS_TIMEOUT) { 
                /* Set "waiting" flag */
                if (waiting!=1) {
                    vegas_status_lock_safe(&st);
                    hputs(st.buf, STATUS_KEY, "waiting");
                    vegas_status_unlock_safe(&st);
                    waiting=1;
                }
                continue; 
            } else {
                vegas_error("vegas_net_thread", 
                        "vegas_udp_wait returned error");
                perror("vegas_udp_wait");
                pthread_exit(NULL);
            }
        }
	
        /* Read packet */
        rv = vegas_udp_recv(&up, &p, bw_mode);
        if (rv!=VEGAS_OK) {
            if (rv==VEGAS_ERR_PACKET) {
                #ifdef DEBUG_NET
                vegas_warn("vegas_net_thread", "Incorrect pkt size");
                #endif
                continue; 
            } else {
                vegas_error("vegas_net_thread", 
                        "vegas_udp_recv returned error");
                perror("vegas_udp_recv");
                pthread_exit(NULL);
            }
        }
	
        /* Update status if needed */
        if (waiting!=0) {
            vegas_status_lock_safe(&st);
            hputs(st.buf, STATUS_KEY, "receiving");
            vegas_status_unlock_safe(&st);
            waiting=0;
        }

        /* Check seq num diff */
        heap_cntr = vegas_spead_packet_heap_cntr(&p);
        heap_offset = vegas_spead_packet_heap_offset(&p);
        seq_num = vegas_spead_packet_seq_num(heap_cntr, heap_offset, packets_per_heap);

        heap_cntr_diff = heap_cntr - last_heap_cntr;
        seq_num_diff = (int)(seq_num - last_seq_num);
        
        last_seq_num = seq_num;
        last_heap_cntr = heap_cntr;

        if (seq_num_diff<=0) { 

            if (seq_num_diff<-1024)
            {
                force_new_block=1;
                obs_started = 1;

                #ifdef DEBUG_NET
                printf("Debug: observation started\n");
                #endif
            }
            else if (seq_num_diff==0) {
                sprintf(msg, "Received duplicate packet (seq_num=%d)", seq_num);
                vegas_warn("vegas_net_thread", msg);
            }
            else  {
                #ifdef DEBUG_NET
                sprintf(msg, "out of order packet. Diff = %d", seq_num_diff);
                vegas_warn("vegas_net_thread", msg);
                #endif
                continue;   /* No going backwards */
            }
        } else { 
            force_new_block=0; 
            npacket_total += seq_num_diff;
            ndropped_total += seq_num_diff - 1;
            npacket_this_block += seq_num_diff;
            fblock->pkts_dropped += seq_num_diff - 1;

            #ifdef DEBUG_NET
            if(seq_num_diff > 1)
            {
                sprintf(msg, "Missing packet. seq_num_diff = %d", seq_num_diff);
                vegas_warn("vegas_net_thread", msg);
            }
            #endif

        }

        /* If obs has not started, ignore this packet */
        if(!obs_started)
        {
            fblock->pkts_dropped = 0;
            npacket_total = 0;
            ndropped_total = 0;
            npacket_this_block = 0;

            continue;
        }

        /* Determine if we go to next block */
        if (heap_cntr>=nextblock_heap_cntr || force_new_block)
        {
            /* Update drop stats */
            if (npacket_this_block > 0)  
                drop_frac_avg = (1.0-drop_lpf)*drop_frac_avg 
                    + drop_lpf *
                    (double)fblock->pkts_dropped / (double)npacket_this_block;

            vegas_status_lock_safe(&st);
            hputi8(st.buf, "NPKT", npacket_total);
            hputi8(st.buf, "NDROP", ndropped_total);
            hputr8(st.buf, "DROPAVG", drop_frac_avg);
            hputr8(st.buf, "DROPTOT", 
                    npacket_total ? 
                    (double)ndropped_total/(double)npacket_total 
                    : 0.0);
            hputi4(st.buf, "NETBLKOU", fblock->block_idx);
            vegas_status_unlock_safe(&st);
            
            /* Finalize first block, and push it off the list.
             * Then grab next available block.
             */
            if (fblock->block_idx>=0) finalize_block(fblock);
            block_stack_push(blocks, nblock);
            increment_block(lblock, heap_cntr);
            curdata = vegas_databuf_data(db, lblock->block_idx);
            curheader = vegas_databuf_header(db, lblock->block_idx);
            curindex = vegas_databuf_index(db, lblock->block_idx);
            nextblock_heap_cntr = lblock->heap_idx + heaps_per_block;
            npacket_this_block = 0;

            /* If new obs started, reset total counters, get start
             * time.  Start time is rounded to nearest integer
             * second, with warning if we're off that by more
             * than 100ms.  Any current blocks on the stack
             * are also finalized/reset */            

            if (force_new_block) {
            
                /* Reset stats */
                npacket_total=0;
                ndropped_total=0;
                npacket_this_block = 0;

                /* Get obs start time */
                get_current_mjd_double(&meas_stt_mjd);
                
                printf("vegas_net_thread: got start packet at MJD %f", meas_stt_mjd);
                
                meas_stt_offs = meas_stt_mjd*24*60*60 - floor(meas_stt_mjd*24*60*60);

                if(meas_stt_offs > 0.1 && meas_stt_offs < 0.9)
                { 
                    char msg[256];
                    sprintf(msg, 
                            "Second fraction = %3.1f ms > +/-100 ms",
                            meas_stt_offs*1e3);
                    vegas_warn("vegas_net_thread", msg);
                }

                vegas_status_lock_safe(&st);
                hputnr8(st.buf, "M_STTMJD", 8, meas_stt_mjd);
                hputr8(st.buf, "M_STTOFF", meas_stt_offs);
                vegas_status_unlock_safe(&st);

                /* Warn if 1st packet number is not zero */
                if (seq_num!=0) {
                    char msg[256];
                    sprintf(msg, "First packet number is not 0 (seq_num=%d)", seq_num);
                    vegas_warn("vegas_net_thread", msg);
                }
            
            }
            
            /* Read current status shared mem */
            vegas_status_lock_safe(&st);
            memcpy(status_buf, st.buf, VEGAS_STATUS_SIZE);
            vegas_status_unlock_safe(&st);

            /* Wait for new block to be free, then clear it
             * if necessary and fill its header with new values.
             */
            while ((rv=vegas_databuf_wait_free(db, lblock->block_idx)) 
                    != VEGAS_OK) {
                if (rv==VEGAS_TIMEOUT) {
                    waiting=1;
                    vegas_warn("vegas_net_thread", "timeout while waiting for output block\n");
                    vegas_status_lock_safe(&st);
                    hputs(st.buf, STATUS_KEY, "blocked");
                    vegas_status_unlock_safe(&st);
                    continue;
                } else {
                    vegas_error("vegas_net_thread", 
                            "error waiting for free databuf");
                    run=0;
                    pthread_exit(NULL);
                    break;
                }
            }
            memcpy(curheader, status_buf, VEGAS_STATUS_SIZE);
            memset(curdata, 0, block_size);
            memset(curindex, 0, db->index_size);
        }

        /* Copy packet into any blocks where it belongs.
         * The "write packets" functions also update drop stats 
         * for blocks, etc.
         */
        int nblocks = 0;
        for (i=0; i<nblock; i++)
        {
            if ((blocks[i].block_idx>=0) && (block_heap_check(&blocks[i],heap_cntr)==0))
            {
            	if (nblocks > 0) {
            		printf("vegas_net_thread: Warning! Adding packet to more than one block! heap_cntr= %d, block = %d",heap_cntr,i);
            	}
            	nblocks++;
                write_spead_packet_to_block(&blocks[i], &p, heap_cntr,
                                heap_offset, packets_per_heap, bw_mode);
            }
        }

        /* Will exit if thread has been cancelled */
        pthread_testcancel();
    }

    pthread_exit(NULL);

    /* Have to close all push's */
    pthread_cleanup_pop(0); /* Closes push(vegas_udp_close) */
    pthread_cleanup_pop(0); /* Closes set_exit_status */
    pthread_cleanup_pop(0); /* Closes vegas_free_psrfits */
    pthread_cleanup_pop(0); /* Closes vegas_status_detach */
    pthread_cleanup_pop(0); /* Closes vegas_databuf_detach */
}
void vegas_null_thread(void *_args) {

    int rv;
    /* Set cpu affinity */
    cpu_set_t cpuset, cpuset_orig;
    sched_getaffinity(0, sizeof(cpu_set_t), &cpuset_orig);
    CPU_ZERO(&cpuset);
    CPU_SET(6, &cpuset);
    rv = sched_setaffinity(0, sizeof(cpu_set_t), &cpuset);
    if (rv<0) { 
        vegas_error("vegas_null_thread", "Error setting cpu affinity.");
        perror("sched_setaffinity");
    }

    /* Set priority */
    rv = setpriority(PRIO_PROCESS, 0, 0);
    if (rv<0) {
        vegas_error("vegas_null_thread", "Error setting priority level.");
        perror("set_priority");
    }

    /* Get args */
    struct vegas_thread_args *args = (struct vegas_thread_args *)_args;

    /* Attach to status shared mem area */
    struct vegas_status st;
    rv = vegas_status_attach(&st);
    if (rv!=VEGAS_OK) {
        vegas_error("vegas_null_thread", 
                "Error attaching to status shared memory.");
        pthread_exit(NULL);
    }
    pthread_cleanup_push((void *)vegas_status_detach, &st);
    pthread_cleanup_push((void *)set_exit_status, &st);

    /* Init status */
    vegas_status_lock_safe(&st);
    hputs(st.buf, STATUS_KEY, "init");
    vegas_status_unlock_safe(&st);

    /* Attach to databuf shared mem */
    struct vegas_databuf *db;
    db = vegas_databuf_attach(args->input_buffer);
    if (db==NULL) {
        vegas_error("vegas_null_thread",
                "Error attaching to databuf shared memory.");
        pthread_exit(NULL);
    }
    pthread_cleanup_push((void *)vegas_databuf_detach, db);

    /* Loop */
    char *ptr;
    struct vegas_params gp;
#if FITS_TYPE == PSRFITS
    struct psrfits pf;
    pf.sub.dat_freqs = NULL;
    pf.sub.dat_weights = NULL;
    pf.sub.dat_offsets = NULL;
    pf.sub.dat_scales = NULL;
    pthread_cleanup_push((void *)vegas_free_psrfits, &pf);
#else
    struct sdfits pf;
    pthread_cleanup_push((void *)vegas_free_sdfits, &pf);
#endif
    int curblock=0;
    signal(SIGINT,cc);
    while (run) {

        /* Note waiting status */
        vegas_status_lock_safe(&st);
        hputs(st.buf, STATUS_KEY, "waiting");
        vegas_status_unlock_safe(&st);

        /* Wait for buf to have data */
        rv = vegas_databuf_wait_filled(db, curblock);
        if (rv!=0) {
            //sleep(1);
            continue;
        }

        /* Note waiting status, current block */
        vegas_status_lock_safe(&st);
        hputs(st.buf, STATUS_KEY, "discarding");
        hputi4(st.buf, "DSKBLKIN", curblock);
        vegas_status_unlock_safe(&st);

        /* Get params */
        ptr = vegas_databuf_header(db, curblock);
        vegas_read_obs_params(ptr, &gp, &pf);

        /* Output if data was lost */
#if FITS_TYPE == PSRFITS
        if (gp.n_dropped!=0 && 
                (gp.packetindex==0 || strcmp(pf.hdr.obs_mode,"SEARCH"))) {
            printf("Block beginning with pktidx=%lld dropped %d packets\n",
                    gp.packetindex, gp.n_dropped);
            fflush(stdout);
        }
#else
        if (gp.num_pkts_dropped!=0 && gp.num_pkts_rcvd!=0) {
            printf("Block received %d packets and dropped %d packets\n",
                    gp.num_pkts_rcvd, gp.num_pkts_dropped);
            fflush(stdout);
        }
#endif

        /* Mark as free */
        vegas_databuf_set_free(db, curblock);

        /* Go to next block */
        curblock = (curblock + 1) % db->n_block;

        /* Check for cancel */
        pthread_testcancel();

    }

    pthread_exit(NULL);

    pthread_cleanup_pop(0); /* Closes set_exit_status */
    pthread_cleanup_pop(0); /* Closes vegas_free_psrfits */
    pthread_cleanup_pop(0); /* Closes vegas_status_detach */
    pthread_cleanup_pop(0); /* Closes vegas_databuf_detach */

}
void vegas_rawdisk_thread(void *_args) {

    /* Set cpu affinity */
    cpu_set_t cpuset, cpuset_orig;
    sched_getaffinity(0, sizeof(cpu_set_t), &cpuset_orig);
    CPU_ZERO(&cpuset);
    CPU_SET(6, &cpuset);
    int rv = sched_setaffinity(0, sizeof(cpu_set_t), &cpuset);
    if (rv<0) { 
        vegas_error("vegas_rawdisk_thread", "Error setting cpu affinity.");
        perror("sched_setaffinity");
    }

    /* Get args */
    struct vegas_thread_args *args = (struct vegas_thread_args *)_args;

    /* Set priority */
    rv = setpriority(PRIO_PROCESS, 0, 0);
    if (rv<0) {
        vegas_error("vegas_rawdisk_thread", "Error setting priority level.");
        perror("set_priority");
    }

    /* Attach to status shared mem area */
    struct vegas_status st;
    rv = vegas_status_attach(&st);
    if (rv!=VEGAS_OK) {
        vegas_error("vegas_rawdisk_thread", 
                "Error attaching to status shared memory.");
        pthread_exit(NULL);
    }
    pthread_cleanup_push((void *)vegas_status_detach, &st);
    pthread_cleanup_push((void *)set_exit_status, &st);

    /* Init status */
    vegas_status_lock_safe(&st);
    hputs(st.buf, STATUS_KEY, "init");
    vegas_status_unlock_safe(&st);

    /* Read in general parameters */
    struct vegas_params gp;
    struct sdfits sf;
    pthread_cleanup_push((void *)vegas_free_sdfits, &sf);

    /* Attach to databuf shared mem */
    struct vegas_databuf *db;
    db = vegas_databuf_attach(args->input_buffer);
    if (db==NULL) {
        vegas_error("vegas_rawdisk_thread",
                "Error attaching to databuf shared memory.");
        pthread_exit(NULL);
    }
    pthread_cleanup_push((void *)vegas_databuf_detach, db);

    /* Init output file */
    FILE *fraw = NULL;
    pthread_cleanup_push((void *)safe_fclose, fraw);

    /* Loop */
    int blocksize=0;
    int curblock=0, dataset;
    int block_count=0, blocks_per_file=128, filenum=0;
    int first=1;
    char *ptr;
    float *data_array;
    struct databuf_index* db_index;

    signal(SIGINT,cc);

    while (run) {

        /* Note waiting status */
        vegas_status_lock_safe(&st);
        hputs(st.buf, STATUS_KEY, "waiting");
        vegas_status_unlock_safe(&st);

        /* Wait for buf to have data */
        rv = vegas_databuf_wait_filled(db, curblock);
        if (rv!=0) continue;

        /* Read param struct and index for this block */
        ptr = vegas_databuf_header(db, curblock);
        db_index = (struct databuf_index*)(vegas_databuf_index(db, curblock));

        /* If first time running */
        if (first==1)
        {
            first = 0;
            vegas_read_obs_params(ptr, &gp, &sf);

            char fname[256];
            sprintf(fname, "%s_%4d.raw", sf.basefilename, filenum);
            fprintf(stderr, "Opening raw file '%s'\n", fname);
            // TODO: check for file exist.
            fraw = fopen(fname, "wb");
            if (fraw==NULL) {
                vegas_error("vegas_rawdisk_thread", "Error opening file.");
                pthread_exit(NULL);
            }
        }
        else
            vegas_read_subint_params(ptr, &gp, &sf);

        /* See if we need to open next file */
        if (block_count >= blocks_per_file) {
            fclose(fraw);
            filenum++;
            char fname[256];
            sprintf(fname, "%s_%4d.raw", sf.basefilename, filenum);
            fprintf(stderr, "Opening raw file '%s'\n", fname);
            fraw = fopen(fname, "wb");
            if (fraw==NULL) {
                vegas_error("vegas_rawdisk_thread", "Error opening file.");
                pthread_exit(NULL);
            }
            block_count=0;
        }

        /* Get full data block size */
        hgeti4(ptr, "BLOCSIZE", &blocksize);

        /* Note writing status and current block */
        vegas_status_lock_safe(&st);
        hputi4(st.buf, "DSKBLKIN", curblock);
        hputs(st.buf, STATUS_KEY, "writing");
        vegas_status_unlock_safe(&st);

        /* Write all data arrays to disk */
        for(dataset = 0; dataset < db_index->num_datasets; dataset++)
        {
            data_array = (float*)(vegas_databuf_data(db, curblock) +
                                     db_index->disk_buf[dataset].array_offset);

            rv = fwrite(data_array, 4, (size_t)(db_index->array_size/4), fraw);

            if (rv != db_index->array_size/4) { 
                vegas_error("vegas_rawdisk_thread", 
                        "Error writing data.");
            }
        }

        /* Increment block counter */
        block_count++;

        /* flush output */
        fflush(fraw);

        /* Mark as free */
        vegas_databuf_set_free(db, curblock);

        /* Go to next block */
        curblock = (curblock + 1) % db->n_block;

        /* Check for cancel */
        pthread_testcancel();

    }

    pthread_exit(NULL);

    pthread_cleanup_pop(0); /* Closes fclose */
    pthread_cleanup_pop(0); /* Closes vegas_databuf_detach */
    pthread_cleanup_pop(0); /* Closes vegas_free_psrfits */
    pthread_cleanup_pop(0); /* Closes set_exit_status */
    pthread_cleanup_pop(0); /* Closes vegas_status_detach */

}
int main(int argc, char *argv[]) {

    static struct option long_opts[] = {
        {"help",    0, NULL, 'h'},
        {"disk",    0, NULL, 'd'},
        {"only_net",0, NULL, 'o'},
        {0,0,0,0}
    };
    int opt, opti;
    int disk=0, only_net=0;
    while ((opt=getopt_long(argc,argv,"hdo",long_opts,&opti))!=-1) {
        switch (opt) {
            case 'd':
                disk=1;
                break;
            case 'o':
                only_net=1;
                break;
            default:
            case 'h':
                usage();
                exit(0);
                break;
        }
    }

    /* Net thread args */
    struct vegas_thread_args net_args;
    vegas_thread_args_init(&net_args);
    net_args.output_buffer = 1;

    /* Init shared mem */
    struct vegas_status stat;
    struct vegas_databuf *dbuf=NULL;
    int rv = vegas_status_attach(&stat);
    if (rv!=VEGAS_OK) {
        fprintf(stderr, "Error connecting to vegas_status\n");
        exit(1);
    }
    dbuf = vegas_databuf_attach(net_args.output_buffer);
    /* If attach fails, first try to create the databuf */
    if (dbuf==NULL) 
#ifdef NEW_GBT
        dbuf = vegas_databuf_create(24, 32*1024*1024, net_args.output_buffer, CPU_INPUT_BUF);
#else
        dbuf = vegas_databuf_create(24, 32*1024*1024, net_args.output_buffer);
#endif
     /* If that also fails, exit */
    if (dbuf==NULL) {
        fprintf(stderr, "Error connecting to vegas_databuf\n");
        exit(1);
    }
    vegas_databuf_clear(dbuf);

    run=1;
    signal(SIGINT, cc);

    /* Launch net thread */
    pthread_t net_thread_id;
    rv = pthread_create(&net_thread_id, NULL, vegas_net_thread,
            (void *)&net_args);
    if (rv) { 
        fprintf(stderr, "Error creating net thread.\n");
        perror("pthread_create");
        exit(1);
    }

    /* Launch raw disk (or null) thread */
    struct vegas_thread_args null_args;
    vegas_thread_args_init(&null_args);
    null_args.input_buffer = net_args.output_buffer;
    pthread_t disk_thread_id=0;
    if (only_net==0) {
        if (disk)
            rv = pthread_create(&disk_thread_id, NULL, vegas_rawdisk_thread, 
                    (void *)&null_args);
        else
            rv = pthread_create(&disk_thread_id, NULL, vegas_null_thread, 
                    (void *)&null_args);
        if (rv) { 
            fprintf(stderr, "Error creating null thread.\n");
            perror("pthread_create");
            exit(1);
        }
    }

    /* Wait for end */
    while (run) { sleep(1); }
    if (disk_thread_id) pthread_cancel(disk_thread_id);
    pthread_cancel(net_thread_id);
    if (disk_thread_id) pthread_kill(disk_thread_id,SIGINT);
    pthread_kill(net_thread_id,SIGINT);
    pthread_join(net_thread_id,NULL);
    printf("Joined net thread\n"); fflush(stdout); fflush(stderr);
    if (disk_thread_id) {
        pthread_join(disk_thread_id,NULL);
        printf("Joined disk thread\n"); fflush(stdout); fflush(stderr);
    }

    vegas_thread_args_destroy(&null_args);

    exit(0);
}
Exemple #8
0
int main(int argc, char *argv[]) {

    /* thread args */
    struct vegas_thread_args net_args, pfb_args, accum_args, disk_args;
    vegas_thread_args_init(&net_args);
    vegas_thread_args_init(&pfb_args);
    vegas_thread_args_init(&accum_args);
    vegas_thread_args_init(&disk_args);

    net_args.output_buffer = 1;
    pfb_args.input_buffer = net_args.output_buffer;
    pfb_args.output_buffer = 2;
    accum_args.input_buffer = pfb_args.output_buffer;
    accum_args.output_buffer = 3;
    disk_args.input_buffer = accum_args.output_buffer;

    /* Init status shared mem */
    struct vegas_status stat;
    int rv = vegas_status_attach(&stat);
    if (rv!=VEGAS_OK) {
        fprintf(stderr, "Error connecting to vegas_status\n");
        exit(1);
    }

    hputs(stat.buf, "BW_MODE", "low");
    hputs(stat.buf, "SWVER", SWVER);

    /* Init first shared data buffer */
    struct vegas_databuf *gpu_input_dbuf=NULL;
    gpu_input_dbuf = vegas_databuf_attach(pfb_args.input_buffer);

    /* If attach fails, first try to create the databuf */
    if (gpu_input_dbuf==NULL) 
        gpu_input_dbuf = vegas_databuf_create(24, 32*1024*1024,
                            pfb_args.input_buffer, GPU_INPUT_BUF);

    /* If that also fails, exit */
    if (gpu_input_dbuf==NULL) {
        fprintf(stderr, "Error connecting to gpu_input_dbuf\n");
        exit(1);
    }

    vegas_databuf_clear(gpu_input_dbuf);

    /* Init second shared data buffer */
    struct vegas_databuf *cpu_input_dbuf=NULL;
    cpu_input_dbuf = vegas_databuf_attach(accum_args.input_buffer);

    /* If attach fails, first try to create the databuf */
    if (cpu_input_dbuf==NULL) 
        cpu_input_dbuf = vegas_databuf_create(24, 32*1024*1024,
                            accum_args.input_buffer, CPU_INPUT_BUF);

    /* If that also fails, exit */
    if (cpu_input_dbuf==NULL) {
        fprintf(stderr, "Error connecting to cpu_input_dbuf\n");
        exit(1);
    }

    vegas_databuf_clear(cpu_input_dbuf);

    /* Init third shared data buffer */
    struct vegas_databuf *disk_input_dbuf=NULL;
    disk_input_dbuf = vegas_databuf_attach(disk_args.input_buffer);

    /* If attach fails, first try to create the databuf */
    if (disk_input_dbuf==NULL) 
        disk_input_dbuf = vegas_databuf_create(16, 16*1024*1024,
                            disk_args.input_buffer, DISK_INPUT_BUF);

    /* If that also fails, exit */
    if (disk_input_dbuf==NULL) {
        fprintf(stderr, "Error connecting to disk_input_dbuf\n");
        exit(1);
    }

    /* Resize the blocks in the disk input buffer, based on the exposure parameter */
    struct vegas_params vegas_p;
    struct sdfits sf;
    vegas_read_obs_params(stat.buf, &vegas_p, &sf);
    vegas_read_subint_params(stat.buf, &vegas_p, &sf);

    long long int num_exp_per_blk = (int)(ceil(DISK_WRITE_INTERVAL / sf.data_columns.exposure));
    long long int disk_block_size = num_exp_per_blk * (sf.hdr.nchan * sf.hdr.nsubband * 4 * 4);
    disk_block_size = disk_block_size > (long long int)(32*1024*1024) ? (long long int)(32*1024*1024) : disk_block_size;

    vegas_conf_databuf_size(disk_input_dbuf, disk_block_size);
    vegas_databuf_clear(disk_input_dbuf);

    signal(SIGINT, cc);

    /* Launch net thread */
    pthread_t net_thread_id;
#ifdef FAKE_NET
    rv = pthread_create(&net_thread_id, NULL, vegas_fake_net_thread,
            (void *)&net_args);
#else
    rv = pthread_create(&net_thread_id, NULL, vegas_net_thread,
            (void *)&net_args);
#endif
    if (rv) { 
        fprintf(stderr, "Error creating net thread.\n");
        perror("pthread_create");
        exit(1);
    }

    /* Launch PFB thread */
    pthread_t pfb_thread_id;

    rv = pthread_create(&pfb_thread_id, NULL, vegas_pfb_thread, (void *)&pfb_args);

    if (rv) { 
        fprintf(stderr, "Error creating PFB thread.\n");
        perror("pthread_create");
        exit(1);
    }

    /* Launch accumulator thread */
    pthread_t accum_thread_id;

    rv = pthread_create(&accum_thread_id, NULL, vegas_accum_thread, (void *)&accum_args);

    if (rv) { 
        fprintf(stderr, "Error creating accumulator thread.\n");
        perror("pthread_create");
        exit(1);
    }

    /* Launch RAW_DISK thread, SDFITS disk thread, or PSRFITS disk thread */
    pthread_t disk_thread_id;
#ifdef RAW_DISK
    rv = pthread_create(&disk_thread_id, NULL, vegas_rawdisk_thread, 
        (void *)&disk_args);
#elif defined NULL_DISK
    rv = pthread_create(&disk_thread_id, NULL, vegas_null_thread, 
        (void *)&disk_args);
#elif defined EXT_DISK
    rv = 0;
#elif FITS_TYPE == PSRFITS
    rv = pthread_create(&disk_thread_id, NULL, vegas_psrfits_thread, 
        (void *)&disk_args);
#elif FITS_TYPE == SDFITS
    rv = pthread_create(&disk_thread_id, NULL, vegas_sdfits_thread, 
        (void *)&disk_args);
#endif
    if (rv) { 
        fprintf(stderr, "Error creating disk thread.\n");
        perror("pthread_create");
        exit(1);
    }

    /* Wait for end */
    run=1;
    while (run) { 
        sleep(1); 
        if (disk_args.finished) run=0;
    }
 
#ifndef EXT_DISK
    pthread_cancel(disk_thread_id);
#endif
    pthread_cancel(pfb_thread_id);
    pthread_cancel(accum_thread_id);
    pthread_cancel(net_thread_id);
#ifndef EXT_DISK
    pthread_kill(disk_thread_id,SIGINT);
#endif
    pthread_kill(accum_thread_id,SIGINT);
    pthread_kill(pfb_thread_id,SIGINT);
    pthread_kill(net_thread_id,SIGINT);
    pthread_join(net_thread_id,NULL);
    printf("Joined net thread\n"); fflush(stdout);
    pthread_join(pfb_thread_id,NULL);
    printf("Joined PFB thread\n"); fflush(stdout);
    pthread_join(accum_thread_id,NULL);
    printf("Joined accumulator thread\n"); fflush(stdout);
#ifndef EXT_DISK
    pthread_join(disk_thread_id,NULL);
    printf("Joined disk thread\n"); fflush(stdout);
#endif
    vegas_thread_args_destroy(&net_args);
    vegas_thread_args_destroy(&pfb_args);
    vegas_thread_args_destroy(&accum_args);
    vegas_thread_args_destroy(&disk_args);

    exit(0);
}
void vegas_pfb_thread(void *_args) {

    /* Get args */
    struct vegas_thread_args *args = (struct vegas_thread_args *)_args;
    int rv;

    /* Set cpu affinity */
    cpu_set_t cpuset, cpuset_orig;
    sched_getaffinity(0, sizeof(cpu_set_t), &cpuset_orig);
    //CPU_ZERO(&cpuset);
    CPU_CLR(13, &cpuset);
    CPU_SET(11, &cpuset);
    rv = sched_setaffinity(0, sizeof(cpu_set_t), &cpuset);
    if (rv<0) { 
        vegas_error("vegas_pfb_thread", "Error setting cpu affinity.");
        perror("sched_setaffinity");
    }

    /* Set priority */
    rv = setpriority(PRIO_PROCESS, 0, args->priority);
    if (rv<0) {
        vegas_error("vegas_pfb_thread", "Error setting priority level.");
        perror("set_priority");
    }

    /* Attach to status shared mem area */
    struct vegas_status st;
    rv = vegas_status_attach(&st);
    if (rv!=VEGAS_OK) {
        vegas_error("vegas_pfb_thread", 
                "Error attaching to status shared memory.");
        pthread_exit(NULL);
    }
    pthread_cleanup_push((void *)vegas_status_detach, &st);
    pthread_cleanup_push((void *)set_exit_status, &st);
    pthread_cleanup_push((void *)vegas_thread_set_finished, args);

    /* Init status */
    vegas_status_lock_safe(&st);
    hputs(st.buf, STATUS_KEY, "init");
    vegas_status_unlock_safe(&st);

    /* Init structs */
    struct vegas_params gp;
    struct sdfits sf;
    pthread_cleanup_push((void *)vegas_free_sdfits, &sf);

    /* Attach to databuf shared mem */
    struct vegas_databuf *db_in, *db_out;
    db_in = vegas_databuf_attach(args->input_buffer);
    if (db_in==NULL) {
        char msg[256];
        sprintf(msg, "Error attaching to databuf(%d) shared memory.",
                args->input_buffer);
        vegas_error("vegas_pfb_thread", msg);
        pthread_exit(NULL);
    }
    pthread_cleanup_push((void *)vegas_databuf_detach, db_in);
    db_out = vegas_databuf_attach(args->output_buffer);
    if (db_out==NULL) {
        char msg[256];
        sprintf(msg, "Error attaching to databuf(%d) shared memory.",
                args->output_buffer);
        vegas_error("vegas_pfb_thread", msg);
        pthread_exit(NULL);
    }
    pthread_cleanup_push((void *)vegas_databuf_detach, db_out);

    /* Loop */
    char *hdr_in = NULL;
    int curblock_in=0;
    int first=1;
    int acc_len = 0;
    int nchan = 0;
    int nsubband = 0;
    signal(SIGINT,cc);

    vegas_status_lock_safe(&st);
    if (hgeti4(st.buf, "NCHAN", &nchan)==0) {
        fprintf(stderr, "ERROR: %s not in status shm!\n", "NCHAN");
    }
    if (hgeti4(st.buf, "NSUBBAND", &nsubband)==0) {
        fprintf(stderr, "ERROR: %s not in status shm!\n", "NSUBBAND");
    }
    vegas_status_unlock_safe(&st);
    if (EXIT_SUCCESS != init_gpu(db_in->block_size,
                                 db_out->block_size,
                                 nsubband,
                                 nchan))
    {
        (void) fprintf(stderr, "ERROR: GPU initialisation failed!\n");
        run = 0;
    }

    while (run) {

        /* Note waiting status */
        vegas_status_lock_safe(&st);
        hputs(st.buf, STATUS_KEY, "waiting");
        vegas_status_unlock_safe(&st);

        /* Wait for buf to have data */
        rv = vegas_databuf_wait_filled(db_in, curblock_in);
        if (rv!=0) continue;

        /* Note waiting status, current input block */
        vegas_status_lock_safe(&st);
        hputs(st.buf, STATUS_KEY, "processing");
        hputi4(st.buf, "PFBBLKIN", curblock_in);
        vegas_status_unlock_safe(&st);

        hdr_in = vegas_databuf_header(db_in, curblock_in);
        
        /* Get params */
        if (first)
        {
            vegas_read_obs_params(hdr_in, &gp, &sf);
            /* Read required exposure from status shared memory, and calculate
               corresponding accumulation length */
            acc_len = (abs(sf.hdr.chan_bw) * sf.hdr.hwexposr);
        }
        vegas_read_subint_params(hdr_in, &gp, &sf);

        /* Call PFB function */
        do_pfb(db_in, curblock_in, db_out, first, st, acc_len);

        /* Mark input block as free */
        vegas_databuf_set_free(db_in, curblock_in);
        /* Go to next input block */
        curblock_in = (curblock_in + 1) % db_in->n_block;

        /* Check for cancel */
        pthread_testcancel();

        if (first) {
            first=0;
        }
    }
    run=0;

    //cudaThreadExit();
    pthread_exit(NULL);

    cleanup_gpu();

    pthread_cleanup_pop(0); /* Closes vegas_databuf_detach(out) */
    pthread_cleanup_pop(0); /* Closes vegas_databuf_detach(in) */
    pthread_cleanup_pop(0); /* Closes vegas_free_sdfits */
    pthread_cleanup_pop(0); /* Closes vegas_thread_set_finished */
    pthread_cleanup_pop(0); /* Closes set_exit_status */
    pthread_cleanup_pop(0); /* Closes vegas_status_detach */

}