/* * execute: Takes in the decoded instruction as a uint32_t array, the UM * registers, the segmented memory sequence, the deleted memory * queue, and finally the program counter. The program executes * the instruction, and returns the updated program counter (which * will be incremented in every case except the load program opcode). */ unsigned execute(uint32_t arr[], uint32_t registers[], Seq_T segMem, Seq_T delMem, unsigned pc) { pc++; uint32_t opcode = arr[0]; switch (opcode) { case 0: cond_move(®(arr, 3), ®(arr, 1), ®(arr, 2)); break; case 1: seg_load(segMem, ®(arr, 1), ®(arr, 2), ®(arr, 3)); break; case 2: seg_store(segMem, ®(arr, 1), ®(arr, 2), ®(arr, 3)); break; case 3: add(®(arr, 2), ®(arr, 3), ®(arr, 1)); break; case 4: multiply(®(arr, 1), ®(arr, 2), ®(arr, 3)); break; case 5: divide(®(arr, 1), ®(arr, 2), ®(arr, 3)); break; case 6: nand(®(arr, 2), ®(arr, 3), ®(arr, 1)); break; case 7: halt(segMem, delMem, arr); break; case 8: map_seg(segMem, delMem, ®(arr, 2), ®(arr, 3)); break; case 9: unmap_seg(segMem, delMem, ®(arr, 3)); break; case 10: output(®(arr, 3)); break; case 11: input(®(arr, 3)); break; case 12: load_program(segMem, REG(arr, 2)); pc = REG(arr, 3); break; case 13: load_val(®(arr, 1), arr[2]); break; default: fprintf(stderr, "ERROR: Invalid opcode: %d.", opcode); exit(EXIT_FAILURE); break; } //free(arr); return pc; }
/* In sem and msg case notify the other processes that use it. */ static void mark_segment_removed(int shmid, int type) { struct semid_pool *semaptr; struct msqid_pool *msgq; switch (type) { case SEMGET: semaptr = (struct semid_pool *)map_seg(shmid); #ifdef SYSV_RWLOCK sysv_rwlock_wrlock(&semaptr->rwlock); #else sysv_mutex_lock(&semaptr->mutex); #endif semaptr->gen = -1; /* It is not necessary to wake waiting threads because * if the group of semaphores is acquired by a thread, * the smaptr lock is held, so it is impossible to * reach this point. */ #ifdef SYSV_RWLOCK sysv_rwlock_unlock(&semaptr->rwlock); #else sysv_mutex_unlock(&semaptr->mutex); #endif munmap_seg(shmid, semaptr); break; case MSGGET : msgq = (struct msqid_pool*)map_seg(shmid); #ifdef SYSV_RWLOCK sysv_rwlock_wrlock(&msgq->rwlock); #else sysv_mutex_lock(&msgq->mutex); #endif msgq->gen = -1; #ifdef SYSV_RWLOCK sysv_rwlock_unlock(&msgq->rwlock); #else sysv_mutex_unlock(&msgq->mutex); #endif munmap_seg(shmid, msgq); break; default: break; } }
int semexit(int undoid) { struct sem_undo *suptr; struct sem *semptr; struct shmid_ds *undoseg; if (undoid < 0) { return (-1); } undoseg = shm_find_segment_by_shmid(undoid); /* The UNDO segment must be mapped by only one segment. */ if (undoseg->shm_nattch != 1) { sysvd_print_err("undo segment mapped by more" "than one process\n"); exit(-1); } suptr = (struct sem_undo *)map_seg(undoid); if (suptr == NULL) { sysvd_print_err("no %d undo segment found\n", undoid); return (-1); } /* No locking mechanism is required because only the * client and the daemon can access the UNDO segment. * At this moment the client is disconnected so only * the daemon can modify this segment. */ while (suptr->un_cnt) { struct semid_pool *semaptr; int semid; int semnum; int adjval; int ix; ix = suptr->un_cnt - 1; semid = suptr->un_ent[ix].un_id; semnum = suptr->un_ent[ix].un_num; adjval = suptr->un_ent[ix].un_adjval; semaptr = (struct semid_pool *)map_seg(semid); if (!semaptr) { return (-1); } /* Was it removed? */ if (semaptr->gen == -1 || semaptr->ds.sem_perm.seq != IPCID_TO_SEQ(semid) || (semaptr->ds.sem_perm.mode & SHMSEG_ALLOCATED) == 0) { --suptr->un_cnt; sysvd_print_err("semexit - semid not allocated\n"); continue; } if (semnum >= semaptr->ds.sem_nsems) { --suptr->un_cnt; sysvd_print_err("semexit - semnum out of range\n"); continue; } #ifdef SYSV_RWLOCK #ifdef SYSV_SEMS sysv_rwlock_rdlock(&semaptr->rwlock); #else sysv_rwlock_wrlock(&semaptr->rwlock); #endif //SYSV_SEMS #else sysv_mutex_lock(&semaptr->mutex); /* Nobody can remove the semaphore beteen the check and the * lock acquisition because it must first send a IPC_RMID * to me and I will process that after finishing this function. */ #endif //SYSV_RWLOCK semptr = &semaptr->ds.sem_base[semnum]; #ifdef SYSV_SEMS sysv_mutex_lock(&semptr->sem_mutex); #endif if (ix == suptr->un_cnt - 1 && semid == suptr->un_ent[ix].un_id && semnum == suptr->un_ent[ix].un_num && adjval == suptr->un_ent[ix].un_adjval) { --suptr->un_cnt; if (adjval < 0) { if (semptr->semval < -adjval) semptr->semval = 0; else semptr->semval += adjval; } else { semptr->semval += adjval; } /* TODO multithreaded daemon: * Check again if the semaphore was removed and do * not wake anyone if it was.*/ umtx_wakeup((int *)&semptr->semval, 0); } #ifdef SYSV_SEMS sysv_mutex_unlock(&semptr->sem_mutex); #endif #ifdef SYSV_RWLOCK sysv_rwlock_unlock(&semaptr->rwlock); #else sysv_mutex_unlock(&semaptr->mutex); #endif munmap_seg(semid, semaptr); } munmap_seg(undoid, suptr); return (0); }