void responderPedidos() { t_nodoPedido *nodo; extern sem_t semaforoLista; int32_t pos; extern t_pollThread *pollHilos; extern pthread_rwlock_t mutexHilos; extern pthread_attr_t attr; inicializarHilos(); // creo el poll de hilos :P while (1) { sem_wait(&semaforoLista); pos = buscarHiloDisponible(); if (pos != -1) { sacarDeLaLista(&nodo); // saco una operacion de la lista. // parametrosHilo *paramH = malloc(sizeof(parametrosHilo)); // paramH->socket = nodo->socket; // paramH->nipcRecibido = nodo->paquete; // paramH->pos = pos; nodo->pos=pos; pthread_rwlock_rdlock(&mutexHilos); // por las dudas, es reg critica pthread_create(&pollHilos[pos].id, &attr, (void*) recibirOperacion, (void*) nodo); pthread_rwlock_unlock(&mutexHilos); } else { sem_post(&semaforoLista); } } }
void servidor(int mi_cliente) { // variables auxiliares MPI_Status status; int origen, tag, rank; nodo_t *server; // numero de pedido recibido (si es que fue enviado) int recv_sequence_number; // cantidad de permisos recibidos int replies; // numero de pedido utilizado // la ultima vez que se pidio permiso al resto de los servidores int used_sequence_number; // cantidad de servidores activos // a los cuales se les pidio permiso la ultima vez int used_servers; // indica si pedimos entrar en la seccion critica int hay_pedido_local = FALSE; // indica si logramos entrar en la seccion critica int en_zona_critica = FALSE; // indica si hay que terminar el proceso int listo_para_salir = FALSE; // el numero para el siguiente pedido int sequence_number = 1; // servidores que estan esperando mi respuesta lista_t* deferred_replies = nuevaLista(); // lista de servidores activos (sin contarme a mi mismo) lista_t* servers = nuevaLista(); for(rank = 0; rank < cant_ranks; rank+= 2) { if(rank != mi_rank) agregarALaLista(rank, servers); } // mientras no tenga que terminar el proceso while( ! listo_para_salir ) { // espero recibir el siguiente mensaje MPI_Recv(&recv_sequence_number, 1, MPI_INT, ANY_SOURCE, ANY_TAG, COMM_WORLD, &status); // obtengo datos del mensaje origen = status.MPI_SOURCE; tag = status.MPI_TAG; // dependiendo del tag switch(tag) { // pedido del cliente para entrar a la seccion critica case TAG_PEDIDO: debug("Mi cliente solicita acceso exclusivo"); assert(origen == mi_cliente); assert(hay_pedido_local == FALSE); assert(en_zona_critica == FALSE); // vamos a pedir entrar a la seccion critica hay_pedido_local = TRUE; // si hay mas servidores if(servers->primero != NULL) { // me preparo para recibir el permiso de los servidores activos replies = 0; used_sequence_number = sequence_number; used_servers = servers->longitud; debugConValorEntero("Solicito acceso exclusivo a los demas servers (sequence number %d)", used_sequence_number); // por cada servidor activo server = servers->primero; while(server != NULL) { // pido permiso con el numero adecuado MPI_Send(&used_sequence_number, 1, MPI_INT, server->elemento, TAG_PEDIDO_S, COMM_WORLD); server = server->siguiente; } // si soy el unico servidor } else { debug("Dándole permiso a mi cliente"); // entro a la zona critica directamente en_zona_critica = TRUE; MPI_Send(NULL, 0, MPI_INT, mi_cliente, TAG_OTORGADO, COMM_WORLD); } // actualizo el numero del siguiente pedido sequence_number++; break; // el cliente libera la seccion critica case TAG_LIBERO: debug("Mi cliente libera su acceso exclusivo"); assert(origen == mi_cliente); assert(hay_pedido_local == TRUE); assert(en_zona_critica == TRUE); // indico que sali de la seccion critica hay_pedido_local = FALSE; en_zona_critica = FALSE; // por cada servidor esperando permisos server = deferred_replies->primero; while(server != NULL) { debugConValorEntero("Dándole permiso a un servidor (rk%d)", server->elemento); // le doy permiso MPI_Send(NULL, 0, MPI_INT, server->elemento, TAG_OTORGADO_S, COMM_WORLD); server = server->siguiente; } // vacio la lista de espera vaciarLaLista(deferred_replies); break; // el cliente termino case TAG_TERMINE: assert(origen == mi_cliente); debug("Mi cliente avisa que terminó"); // por cada servidor activo server = servers->primero; while(server != NULL) { // le aviso que termine MPI_Send(NULL, 0, MPI_INT, server->elemento, TAG_TERMINE_S, COMM_WORLD); server = server->siguiente; } // indico que puedo terminar el proceso listo_para_salir = TRUE; break; // pedido de otro servidor para entrar a la seccion critica case TAG_PEDIDO_S: debugConValorEntero("Un servidor me pide permiso (rk%d)", origen); assert(origen % 2 == 0); // Es de otro srv. // actualizo el numero del siguiente pedido si es necesario if(recv_sequence_number >= sequence_number) sequence_number = recv_sequence_number + 1; // si no estoy esperando para entrar a la seccion critica // (ni estoy en ella) if(!hay_pedido_local) { // doy permiso directamente debugConValorEntero("Dándole permiso a un servidor (rk%d)", origen); MPI_Send(NULL, 0, MPI_INT, origen, TAG_OTORGADO_S, COMM_WORLD); // si estoy esperando para entrar a la seccion critica // (o estoy en ella) } else { // si estoy en seccion critica if(en_zona_critica) { // pongo en lista de espera debugConValorEntero("Dejo a un servidor en espera (rk%d)", origen); agregarALaLista(origen, deferred_replies); // si no estoy en seccion critica } else { // si su numero de pedido es menor // o bien, si son iguales pero su rank es menor if(recv_sequence_number < used_sequence_number || (recv_sequence_number == used_sequence_number && origen < mi_rank)) { // le doy permiso debugConValorEntero("Dándole permiso a un servidor (rk%d)", origen); MPI_Send(NULL, 0, MPI_INT, origen, TAG_OTORGADO_S, COMM_WORLD); } else { // pongo en lista de espera debugConValorEntero("Dejo a un servidor en espera (rk%d)", origen); agregarALaLista(origen, deferred_replies); } } } break; // otro servidor me dio permiso para entrar a la seccion critica case TAG_OTORGADO_S: debugConValorEntero("Un servidor me da permiso (rk%d)", origen); assert(origen % 2 == 0); // Es de otro srv. assert(hay_pedido_local == TRUE); assert(en_zona_critica == FALSE); // me llego un permiso mas replies++; assert(replies <= used_servers); //espero no tener replies de mas // si ya tengo todos los permisos if(replies == used_servers) { debug("Dándole permiso a mi cliente"); // entro en zona critica en_zona_critica = TRUE; MPI_Send(NULL, 0, MPI_INT, mi_cliente, TAG_OTORGADO, COMM_WORLD); } break; // otro servidor termino case TAG_TERMINE_S: debugConValorEntero("Un servidor avisa que terminó (rk%d)", origen); // saco al servidor que termino de la lista de servidores activos sacarDeLaLista(origen, servers); break; // algo invalido default: debug("TAG desconocido"); break; } } // libero memoria free(deferred_replies); free(servers); }