示例#1
0
/*
 * 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(&REG(arr, 3), &REG(arr, 1), &REG(arr, 2));
                        break;
                case 1:
                        seg_load(segMem, &REG(arr, 1), &REG(arr, 2), 
                                &REG(arr, 3));
                        break;
                case 2:
                        seg_store(segMem, &REG(arr, 1), &REG(arr, 2), 
                            &REG(arr, 3));
                        break;
                case 3:
                        add(&REG(arr, 2), &REG(arr, 3), &REG(arr, 1));
                        break;
                case 4:
                        multiply(&REG(arr, 1), &REG(arr, 2), &REG(arr, 3));
                        break;
                case 5:
                        divide(&REG(arr, 1), &REG(arr, 2), &REG(arr, 3));
                        break;
                case 6:
                        nand(&REG(arr, 2), &REG(arr, 3), &REG(arr, 1));
                        break;
                case 7:
                        halt(segMem, delMem, arr);
                        break;
                case 8:
                        map_seg(segMem, delMem, &REG(arr, 2), &REG(arr, 3));
                        break;
                case 9:
                        unmap_seg(segMem, delMem, &REG(arr, 3));
                        break;
                case 10:
                        output(&REG(arr, 3));
                        break;
                case 11:
                        input(&REG(arr, 3));
                        break;
                case 12:
                        load_program(segMem, REG(arr, 2));
                        pc = REG(arr, 3);
                        break;
                case 13:
                        load_val(&REG(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);
}