int init_pipe(struct pipe* p, int n_dst, int q_depth, int buf_sz) { int free_bufs = n_dst * q_depth; struct pipe_elem* msg_all = (struct pipe_elem*)malloc( free_bufs * (sizeof(msg_all[0]) + buf_sz)); void* buf_ptr; int def_dst_n, i; // allocate bufs if (!msg_all) return -1; p->priv = (void*)msg_all; // initialize src if (init_queue(&p->src, free_bufs)) goto free_buf; // initialize dst def_dst_n = sizeof(p->_dst) / sizeof(p->_dst[0]); p->dst = n_dst < def_dst_n ? &p->_dst[0] : (struct queue*)malloc(n_dst * sizeof(p->dst[0])); if (!p->dst) goto free_src; for (i = 0; i < n_dst; i++) { if (init_queue(&p->dst[i], q_depth)) goto free_dst; } // init spinlock if (pthread_spin_init(&p->lock, PTHREAD_PROCESS_PRIVATE)) goto free_dst; // push buffers onto src buf_ptr = (void*)&msg_all[free_bufs]; for (i = 0; i < free_bufs; i++) { msg_all[i].buf = buf_ptr; msg_all[i].seq = 0; msg_all[i].ref_cnt = 0; buf_ptr += buf_sz; assert(!enqueue(&p->src, &msg_all[i])); } p->n_dst = n_dst; return 0; free_dst : for (i--; i >= 0; i--) close_queue(&p->dst[i]); free_src : close_queue(&p->src); free_buf : free(msg_all); destroy_lock : pthread_spin_destroy(&p->lock); return -1; }
void close_pipe(struct pipe* p) { int i; for (i = 0; i < p->n_dst; i++) close_queue(&p->dst[i]); if (p->dst != &p->_dst[0]) free(p->dst); close_queue(&p->src); free(p->priv); pthread_spin_destroy(&p->lock); }
int open_queue( void ) { struct msqid_ds qstat; int oldqid = qid; qstat.msg_qnum = 0; if( qid == -2 ) keyval = ftok( IPC_KEY_FILE, 'm' ); if( msgctl( qid, IPC_STAT, &qstat ) != -1 ) { if( qstat.msg_qnum > 50 ) close_queue( ); } if( ( qid = msgget( keyval, IPC_CREAT | 0666 ) ) == -1 ) { #if defined(__FreeBSD__) bug( "Unable to msgget keyval %ld.", keyval ); #else bug( "Unable to msgget keyval %d.", keyval ); #endif return -1; } if( oldqid != qid ) oldqid = qid; return 1; }
int get_job (job_queue_t *q, job_t *j) { int index; #ifdef NO_CACHE_COHERENCE __k1_rmb(); #endif if(q->begin == q->end && q->status == QUEUE_CLOSED) return 0; COND_VAR_MUTEX_LOCK(q->cond_var); while (q->begin == q->end) { switch (q->status) { case QUEUE_CLOSED: COND_VAR_MUTEX_UNLOCK(q->cond_var); return 0; case QUEUE_WAIT: #ifdef NO_CACHE_COHERENCE waiting_threads++; //see close_queue() COND_VAR_WAIT(q->cond_var); waiting_threads--; #else COND_VAR_WAIT(q->cond_var); #endif break; case QUEUE_OK: q->status = QUEUE_WAIT; reset_queue(q); COND_VAR_MUTEX_UNLOCK(q->cond_var); int jobs_added = q->repopulate_queue(q->repopulate_queue_par); COND_VAR_MUTEX_LOCK(q->cond_var); if (jobs_added) q->status = QUEUE_OK; else close_queue(q); } } index = q->begin++; COND_VAR_MUTEX_UNLOCK(q->cond_var); memcpy(j, &q->buffer[index].tsp_job, sizeof(job_t)); return 1; }
int main(int argc, char *argv[]) { pid_t pid; int i; int users_number; int service_probability; int text_message_probability; int status; int deadproc = 0; /* A counter of the already terminated user processes */ int qid; int sw; /* Qid of the switch */ int dest; /* Destination of the message */ int olddest; /* Destination of the previous message */ int queues[MAXCHILDS + 1]; /* Queue identifiers - 0 is the qid of the switch */ int msg_sender; int msg_recipient; char msg_text[160]; int msg_service; int msg_service_data; int t; int timing[MAXCHILDS + 1][2]; int unreachable_destinations[MAXCHILDS + 1]; char *padding = " "; char text[160]; messagebuf_t msg, in; /* Command line argument parsing */ if(argc != 4){ usage(argv); exit(0); } users_number = strtol(argv[1], NULL, 10); service_probability = strtol(argv[2], NULL, 10); text_message_probability = strtol(argv[3], NULL, 10); if((users_number < MINCHILDS) || (users_number > MAXCHILDS)){ usage(argv); exit(1); } if((service_probability < 0) || (service_probability > 100)){ usage(argv); exit(0); } if((text_message_probability < 0) || (text_message_probability > 100)){ usage(argv); exit(0); } printf("Number of users: %d\n", users_number); printf("Probability of a service request: %d%%\n", service_probability); printf("Probability of a text message: %d%%\n", text_message_probability); printf("\n"); /* Initialize the random number generator */ srandom(time(NULL)); /* Switch queue initialization */ sw = init_queue(255); /* Read the last messages we have in the queue */ while(receive_message(sw, TYPE_TEXT, &in)){ printf("%d -- S -- Receiving old text messages\n", (int) time(NULL), i); } /* Read the last messages we have in the queue */ while(receive_message(sw, TYPE_SERVICE, &in)){ printf("%d -- S -- Receiving old service messge\n", (int) time(NULL), i); } /* All queues are "uninitialized" (set equal to switch queue) */ for(i = 0; i <= users_number; i++){ queues[i] = sw; unreachable_destinations[i] = 0; } /* Create users */ for(i = 1; i <= users_number; i++){ pid = fork(); if (pid == 0){ srandom(time(NULL) + 1000*i); /* Initialize queue */ qid = init_queue(i); /* Read the last messages we have in the queue */ while(receive_message(qid, TYPE_TEXT, &in)){ printf("%s%d -- U %02d -- Receiving old text messages\n", padding, (int) time(NULL), i); } /* Read the last messages we have in the queue */ while(receive_message(qid, TYPE_SERVICE, &in)){ printf("%s%d -- U %02d -- Receiving old service messge\n", padding, (int) time(NULL), i); } /* Let the switch know we are alive */ user_send_connect(i, sw); /* Let the switch know how to reach us */ user_send_qid(i, qid, sw); /* Enter the main loop */ while(1){ sleep(rand()%MAX_SLEEP); /* Check if the switch requested a service */ if(receive_message(qid, TYPE_SERVICE, &in)){ msg_service = get_service(&in); switch(msg_service){ case SERVICE_TERMINATE: /* Send an acknowledgement to the switch */ user_send_disconnect(i, getpid(), sw); /* Read the last messages we have in the queue */ while(receive_message(qid, TYPE_TEXT, &in)){ msg_sender = get_sender(&in); get_text(&in, msg_text); printf("%s%d -- U %02d -- Message received\n", padding, (int) time(NULL), i); printf("%s Sender: %d\n", padding, msg_sender); printf("%s Text: %s\n", padding, msg_text); } /* Remove the queue */ close_queue(qid); printf("%s%d -- U %02d -- Termination\n", padding, (int) time(NULL), i); exit(0); break; case SERVICE_TIME: user_send_time(i, sw); printf("%s%d -- U %02d -- Timing\n", padding, (int) time(NULL), i); break; } } /* Send a message */ if(random_number(100) < text_message_probability){ dest = random_number(users_number + 1); /* Do not send a message to the switch, to yourself and to the previous recipient */ while((dest == 0) || (dest == i) || (dest == olddest)){ dest = random_number(users_number + 1); } olddest = dest; printf("%s%d -- U %02d -- Message to user %d\n", padding, (int) time(NULL), i, dest); sprintf(text, "A message from me (%d) to you (%d)", i, dest); user_send_text_message(i, dest, text, sw); } /* Check the incoming box for simple messages */ if(receive_message(qid, TYPE_TEXT, &in)){ msg_sender = get_sender(&in); get_text(&in, msg_text); printf("%s%d -- U %02d -- Message received\n", padding, (int) time(NULL), i); printf("%s Sender: %d\n", padding, msg_sender); printf("%s Text: %s\n", padding, msg_text); } } } } /* Switch (parent process) */ while(1){ /* Check if some user is answering to service messages */ if(receive_message(sw, TYPE_SERVICE, &in)){ msg_service = get_service(&in); msg_sender = get_sender(&in); switch(msg_service){ case SERVICE_CONNECT: /* A new user has connected */ printf("%d -- S -- Service: connection\n", (int) time(NULL)); printf(" User: %d\n", msg_sender); break; case SERVICE_DISCONNECT: /* The user is terminating */ printf("%d -- S -- Service: disconnection\n", (int) time(NULL)); printf(" User: %d\n", msg_sender); deadproc++; break; case SERVICE_QID: /* The user is sending us its queue id */ msg_service_data = get_service_data(&in); printf("%d -- S -- Service: queue\n", (int) time(NULL)); printf(" User: %d\n", msg_sender); printf(" Qid: %d\n", msg_service_data); queues[msg_sender] = msg_service_data; break; case SERVICE_TIME: msg_service_data = get_service_data(&in); /* Timing informations */ timing[msg_sender][1] = msg_service_data - timing[msg_sender][1]; printf("%d -- S -- Service: timing\n", (int) time(NULL)); printf(" User: %d\n", msg_sender); printf(" Timing: %d\n", timing[msg_sender][1]); /* The user is no more blocked by a timing operation */ timing[msg_sender][0] = 0; break; } } /* Check if some user has connected */ if(receive_message(sw, TYPE_TEXT, &in)){ msg_recipient = get_recipient(&in); msg_sender = get_sender(&in); get_text(&in, msg_text); /* If the destination is connected */ if(queues[msg_recipient] != sw){ /* Send the message (forward it) */ switch_send_text_message(msg_sender, msg_text, queues[msg_recipient]); printf("%d -- S -- Routing message\n", (int) time(NULL)); printf(" Sender: %d -- Destination: %d\n", msg_sender, msg_recipient); printf(" Text: %s\n", msg_text); } else{ unreachable_destinations[msg_sender] += 1; if (unreachable_destinations[msg_sender] > MAXFAILS) { continue; } printf("%d -- S -- Unreachable destination\n", (int) time(NULL)); printf(" Sender: %d -- Destination: %d\n", msg_sender, msg_recipient); printf(" Text: %s\n", msg_text); printf(" Threshold: %d/%d\n", unreachable_destinations[msg_sender], MAXFAILS); if (unreachable_destinations[msg_sender] == MAXFAILS) { printf("%d -- S -- User %d reached max unreachable destinations\n", (int) time(NULL), msg_sender); switch_send_terminate(queues[msg_sender]); /* Remove its queue from the list */ queues[msg_sender] = sw; } } /* Randomly request a service to the sender of the last message */ if((random_number(100) < service_probability) && (queues[msg_sender] != sw)){ if (random_number(100) < 40){ /* The user must terminate */ printf("%d -- S -- User %d chosen for termination\n", (int) time(NULL), msg_sender); switch_send_terminate(queues[msg_sender]); /* Remove its queue from the list */ queues[msg_sender] = sw; } else { /* Check if we are already timing that user */ if(!timing[msg_sender][0]){ timing[msg_sender][0] = 1; timing[msg_sender][1] = (int) time(NULL); printf("%d -- S -- User %d chosen for timing...\n", timing[msg_sender][1], msg_sender); switch_send_time(queues[msg_sender]); } } } } else{ if(deadproc == users_number){ /* All childs have been terminated, just wait for the last to complete its jobs */ waitpid(pid, &status, 0); /* Remove the switch queue */ remove_queue(sw); printf("\n"); printf("No more active users. Switch turns off.\n"); /* Terminate the program */ exit(0); } } } }