void fgCommand(int index) { int size = list_size(lista_trabajos); // Guardamos el tamaño de la lista if(empty_list(lista_trabajos)) { printf("La lista está vacía\n"); } else if(index > size || index <= 0) { printf("El argumento indicado está fuera del rango de la lista\n"); printf("La lista sólo contiene {%d} elementos\n", size); } else { // Extraemos el trabajo de la lista de trabajos job *trabajo = get_item_bypos(lista_trabajos, index); // Información sobre el proceso actual printf("Tarea: %d, pid: %d, comando: %s, estado anterior: %s. \n", index, trabajo->pgid, trabajo->command, state_strings[trabajo->state]); // Si la tarea está parada es que la hemos suspendido if(trabajo->state == STOPPED) { printf("Reanudando la tarea... \n"); killpg(trabajo->pgid, SIGCONT); // Enviamos al proceso la señal para reanudarlo } if(trabajo->state != FOREGROUND) { int status; int pgid; int info; pgid = trabajo->pgid; trabajo->state = FOREGROUND; printf("Tarea: %d, pid: %d, comando: %s, estado actual: %s. \n", index, trabajo->pgid, trabajo->command, state_strings[trabajo->state]); printf("Asignándole el terminal...\n"); set_terminal(pgid); // Esperamos que el proceso siga haciendo su ejecución en primer plano pid_t wpid = waitpid(pgid, &status, WUNTRACED); // Vemos su nuevo estado y damos el mensaje enum status st = analyze_status(status, &info); printf("Background pid: %d, command: %s, %s, info: %d \n", wpid, trabajo->command, status_strings[st], info); block_SIGCHLD(); if(st == SUSPENDED) { // Actualizamos su estado en la lista trabajo->state = STOPPED; // Si no, es que ha terminado y por tanto lo eliminamos de la lista } else { // Lo eliminamos de la lista delete_job(lista_trabajos, trabajo); } unblock_SIGCHLD(); // Le devolvemos al terminal al proceso principal set_terminal(getpid()); } } }
/** Manejador para la señal SIGCHLD **/ void manejador(int senal) { int i; // Recorremos la lista for(i = list_size(lista_trabajos); i >= 1; i--) { // Extraemos un trabajo job *aux = get_item_bypos(lista_trabajos, i); // Si no es de foreground, es decir BACKGROUND O STOPPED if(aux->state != FOREGROUND) { int status; // Vemos si ha cambiado su estado sin bloquearnos (Wait no bloqueante) // es totalmente necesario WNOHANG para no quedarnos bloqueados pid_t wpid = waitpid(aux->pgid, &status, WNOHANG | WUNTRACED); // Si es el caso if(wpid == aux->pgid) { int info; // Vemos su nuevo estado y damos el mensaje enum status st = analyze_status(status, &info); printf("Background pid: %d, command: %s, %s, info: %d \n", wpid, aux->command, status_strings[st], info); // Si se ha suspendido if(st == SUSPENDED) { // Actualizamos su estado en la lista aux->state = STOPPED; // Si no, se trata de un proceso terminado } else { if(aux->state == RESPAWNABLE) { // Restauramos las señales que reciben del terminal restore_terminal_signals(); aux->args[0] = "#"; // Volvemos a ejecutar el comando execvp(aux->command, aux->args); // Solo llegará aquí si no se ha producido el cambio de imagen printf("Error. No se ha podido hacer el respawn: %s\n", aux->command); exit(-1); } // Lo eliminamos de la lista delete_job(lista_trabajos, aux); } } } } }
/* * Description: Called by the upper layers to do the grunt work for * a master read transaction. */ static int iic_readbytes(struct i2c_adapter *adap, char *buf, int count, int xfer_type) { struct iic_regs *iic; int rdcount = 0, i, status, timeout; int loops, remainder, j; int ret, error_code; iic = (struct iic_regs *) IIC_DEV(vaddr); if (count == 0) return 0; loops = count / 4; remainder = count % 4; if ((loops > 1) && (remainder == 0)) { for (i = 0; i < (loops - 1); i++) { /* Issue command to begin master read (4 bytes maximum) */ iic_outb(iic->cntl, 0x37); /* * Wait for transmission to complete. When it does, * loop to the top of the for statement and write the * next four bytes. */ timeout = wait_for_pin(adap, &status); if (timeout < 0) return rdcount; ret = analyze_status(adap, &error_code); if (ret < 0) { if (error_code == IIC_ERR_INCOMPLETE_XFR) return rdcount; else return error_code; } for (j = 0; j < 4; j++) { /* Wait for data to shuffle to top of data buffer * This value needs to optimized. */ udelay(1); buf[rdcount] = iic_inb(iic->mdbuf); rdcount++; } } } else if ((loops >= 1) && (remainder > 0)) { for (i = 0; i < loops; i++) { /* Issue command to begin master read (4 bytes maximum) */ iic_outb(iic->cntl, 0x37); /* * Wait for transmission to complete. When it does, * loop to the top of the for statement and write the * next four bytes. */ timeout = wait_for_pin(adap, &status); if (timeout < 0) return rdcount; ret = analyze_status(adap, &error_code); if (ret < 0) { if (error_code == IIC_ERR_INCOMPLETE_XFR) return rdcount; else return error_code; } for (j = 0; j < 4; j++) { /* Wait for data to shuffle to top of data buffer * This value needs to optimized. */ udelay(1); buf[rdcount] = iic_inb(iic->mdbuf); rdcount++; } } } if (remainder == 0) remainder = 4; DEB2(printk (KERN_DEBUG "iic_readbytes: writing %x to IICO_CNTL\n", (0x03 | ((remainder - 1) << 4)))); if (xfer_type == IIC_COMBINED_XFER) { iic_outb(iic->cntl, (0x0b | ((remainder - 1) << 4))); } else { iic_outb(iic->cntl, (0x03 | ((remainder - 1) << 4))); } DEB2(printk(KERN_DEBUG "iic_readbytes: Wait for pin\n")); timeout = wait_for_pin(adap, &status); DEB2(printk(KERN_DEBUG "iic_readbytes: Got the interrupt\n")); if (timeout < 0) return rdcount; ret = analyze_status(adap, &error_code); if (ret < 0) { if (error_code == IIC_ERR_INCOMPLETE_XFR) return rdcount; else return error_code; } for (i = 0; i < remainder; i++) { buf[rdcount] = iic_inb(iic->mdbuf); rdcount++; } return rdcount; }
static int iic_sendbytes(struct i2c_adapter *adap, const char *buf, int count, int xfer_flag) { struct iic_regs *iic; int wrcount, status, timeout; int loops, remainder, i, j; int ret, error_code; iic = (struct iic_regs *) IIC_DEV(vaddr); if (count == 0) return 0; wrcount = 0; loops = count / 4; remainder = count % 4; if ((loops > 1) && (remainder == 0)) { for (i = 0; i < (loops - 1); i++) { /* Write four bytes to master data buffer */ for (j = 0; j < 4; j++) { iic_outb(iic->mdbuf, buf[wrcount++]); } /* Issue command to IICO device to begin transmission */ iic_outb(iic->cntl, 0x35); /* Wait for transmission to complete. When it does, * loop to the top of the for statement and write the * next four bytes. */ timeout = wait_for_pin(adap, &status); if (timeout < 0) { /* Error handling */ return wrcount; } ret = analyze_status(adap, &error_code); if (ret < 0) { if (error_code == IIC_ERR_INCOMPLETE_XFR) { /* Return the number of bytes transferred */ ret = iic_inb(iic->xfrcnt); ret = ret & 0x07; return (wrcount - 4 + ret); } else return error_code; } } } else if ((loops >= 1) && (remainder > 0)) { /*printk(KERN_DEBUG "iic_sendbytes: (loops >= 1)\n"); */ for (i = 0; i < loops; i++) { /* * Write four bytes to master data buffer */ for (j = 0; j < 4; j++) { iic_outb(iic->mdbuf, buf[wrcount++]); } /* * Issue command to IICO device to begin transmission */ iic_outb(iic->cntl, 0x35); /* * Wait for transmission to complete. When it does, * loop to the top of the for statement and write the * next four bytes. */ timeout = wait_for_pin(adap, &status); if (timeout < 0) return wrcount; ret = analyze_status(adap, &error_code); if (ret < 0) { if (error_code == IIC_ERR_INCOMPLETE_XFR) { /* Return the number of bytes transferred */ ret = iic_inb(iic->xfrcnt); ret = ret & 0x07; return (wrcount - 4 + ret); } else return error_code; } } } if (remainder == 0) remainder = 4; /* Write the remaining bytes (less than or equal to 4) */ for (i = 0; i < remainder; i++) iic_outb(iic->mdbuf, buf[wrcount++]); if (xfer_flag == IIC_COMBINED_XFER) { iic_outb(iic->cntl, (0x09 | ((remainder - 1) << 4))); } else { iic_outb(iic->cntl, (0x01 | ((remainder - 1) << 4))); } DEB2(printk(KERN_DEBUG "iic_sendbytes: Waiting for interrupt\n")); timeout = wait_for_pin(adap, &status); if (timeout < 0) return wrcount; ret = analyze_status(adap, &error_code); if (ret < 0) { if (error_code == IIC_ERR_INCOMPLETE_XFR) { /* Return the number of bytes transferred */ ret = iic_inb(iic->xfrcnt); ret = ret & 0x07; return (wrcount - 4 + ret); } else return error_code; } DEB2(printk(KERN_DEBUG "iic_sendbytes: Got interrupt\n")); return wrcount; }
int main(void) { char inputBuffer[MAX_LINE]; /** buffer to hold the command entered **/ int background; /** equals 1 if a command is followed by '&' **/ int respawnable; /** igual a 1 si al comando le sigue '#' **/ char *args[MAX_LINE / 2]; /** command line (of 256) has max of 128 arguments **/ // probably useful variables: int pid_fork, pid_wait; /** pid for created and waited process **/ int status; /** status returned by wait **/ enum status status_res; /** status processed by analyze_status() **/ int info; /** info processed by analyze_status() **/ ignore_terminal_signals(); /** Ignora las señales del terminal **/ /** Asociamos el manejador a la señal SIGCHLD y creamos la lista de trabajos **/ signal(SIGCHLD, manejador); lista_trabajos = new_list("Lista trabajos"); /** Program terminates normally inside get_command() after ^D is typed **/ while(1) { printf("\nCOMMAND->"); fflush(stdout); /** get next command **/ get_command(inputBuffer, MAX_LINE, args, &background, &respawnable); // if empty command if(args[0] == NULL) { continue; } /** Comando interno CD **/ if(strcmp(args[0], "cd") == 0 && args[1] != NULL) { chdir(args[1]); continue; } /** Comando interno historial **/ if(strcmp(args[0], "historial") == 0) { continue; } /** Comando interno JOBS (HECHO) **/ if(strcmp(args[0], "jobs") == 0) { if(empty_list(lista_trabajos)) { printf("La lista de tareas está vacía\n"); } else { print_job_list(lista_trabajos); } continue; } /** Comando interno BG (HECHO) **/ if(strcmp(args[0], "bg") == 0) { if(args[1] == NULL) { printf("No le has pasado ningún argumento al comando \n"); } else { int index = atoi(args[1]); // Convertimos el indice pasado a un entero bgCommand(index); // Invocamos al comando FG } continue; } /** Comando interno FG (HECHO) **/ if(strcmp(args[0], "fg") == 0) { int index = 1; // Por defecto a la primera tarea de la lista if(args[1] != NULL) { index = atoi(args[1]); // Si no es nulo, lo aplicaremos al correspondiente } fgCommand(index); // Invocamos al comando FG continue; } // the steps are: // (1) fork a child process using fork() pid_fork = fork(); if(pid_fork < 0) { // Caso de error printf("Error. The system wasn able to spawn a new process. Exiting...\n"); exit(-1); } else if(pid_fork == 0) { // Proceso hijo /** Nuevo identificador de grupo de procesos para el hijo, asociacion del terminal y señales a default **/ pid_t mypid = getpid(); new_process_group(mypid); // Metemos al hijo en un nuevo grupo if(!background && !respawnable) { // Le asignamos el terminal set_terminal(mypid); } // Restauramos las señales que reciben del terminal restore_terminal_signals(); // (2) the child process will invoke execvp() execvp(args[0], args); // Solo llegará aquí si no se ha producido el cambio de imagen printf("Error. Command not found: %s\n", args[0]); exit(-1); // Padre } else { /** Nuevo identificador de grupo de procesos para el hijo **/ new_process_group(pid_fork); // El padre se va a un nuevo grupo de trabajo /** Si el programa está en background o es respawnable **/ if(background || respawnable) { /** BLoqueamos la señal SIGCHLD, añadimos el trabajo a la lista(background) y desbloqueamos la señal **/ block_SIGCHLD(); job *aux; // Creamos un nuevo nodo para agregarlo a la lista if(background) { aux = new_job(pid_fork, args[0], args, BACKGROUND); } else if(respawnable) { aux = new_job(pid_fork, args[0], args, RESPAWNABLE); } // Añadimos ese nodo a la lista creada anteriormente add_job(lista_trabajos, aux); unblock_SIGCHLD(); printf("Background job running... pid: %d, command: %s. \n", pid_fork, args[0]); /** Si no, es por que está en foreground **/ } else { /** * Wait con detección de suspension y recuperación del terminal * Con el WUNTRACED se comprueba también si el hijo se suspende **/ set_terminal(pid_fork); // Redundante pid_t wait_pid = waitpid(pid_fork, &status, WUNTRACED); set_terminal(getpid()); /** * pid_fork = waitpid(pid_fork, &status, 0); * esta instruccion ya no es necesaria porque hacemos el wait_pid **/ int info; // Le pasamos la variable "status" que nos acaba de pasar el wait enum status st = analyze_status(status, &info); /** * Si sale del bloqueo debido a la suspensión del estado * lo metemos en la lista de tareas para poder llevar un * seguimiento de los procesos suspendidos **/ if(st == SUSPENDED) { /** BLoqueamos la señal SIGCHLD, añadimos el trabajo a la lista (suspendido) y desbloqueamos la señal **/ block_SIGCHLD(); // Creamos un nuevo nodo para agregarlo a la lista job *aux = new_job(pid_fork, args[0], args, STOPPED); // Añadimos ese nodo a la lista creada anteriormente add_job(lista_trabajos, aux); unblock_SIGCHLD(); } // (4) Shell shows a status message for processed command printf("Foreground pid: %d, command: %s, status: %s, info: %d. \n", wait_pid, args[0], status_strings[st], info); } } // (5) loop returns to get_commnad() function } // end while }