📄 syscall.c
字号:
#if defined(hpux) || defined(__hpux) /* no utimes() in hpux, use utime() instead */ { struct utimbuf ubuf; ubuf.actime = tval[0].tv_sec; ubuf.modtime = tval[1].tv_sec; /* result */regs_R[pid][2] = utime(buf, &ubuf); }#elif defined(__svr4__) || defined(__USLC__) || defined(unix) || defined(_AIX) /* result */regs_R[pid][2] = utimes(buf, tval);#elif defined(__CYGWIN32__) warn("syscall: called utimes\n");#else#error No utimes() implementation!#endif } /* check for an error condition */ if (regs_R[pid][2] != -1) regs_R[pid][7] = 0; else { /* got an error, indicate results */ regs_R[pid][2] = errno; regs_R[pid][7] = 1; } } break; case SS_SYS_getrlimit: case SS_SYS_setrlimit:#if defined(__CYGWIN32__) { warn("syscall: called get/setrlimit\n"); regs_R[pid][7] = 0; }#else { struct rlimit ss_rl; struct rlimit rl; /* copy rlimit structure to host memory */ mem_bcopy(mem_fn, Read, /*rlimit*/regs_R[pid][5], &ss_rl, sizeof(struct ss_rlimit)); /* convert rlimit structure to host format */ rl.rlim_cur = SWAP_WORD(ss_rl.rlim_cur); rl.rlim_max = SWAP_WORD(ss_rl.rlim_max); /* get rlimit information */ if (syscode == SS_SYS_getrlimit) /*result*/regs_R[pid][2] = getrlimit(regs_R[pid][4], &rl); else /* syscode == SS_SYS_setrlimit */ /*result*/regs_R[pid][2] = setrlimit(regs_R[pid][4], &rl); /* check for an error condition */ if (regs_R[pid][2] != -1) regs_R[pid][7] = 0; else { /* got an error, indicate results */ regs_R[pid][2] = errno; regs_R[pid][7] = 1; } /* convert rlimit structure to target format */ ss_rl.rlim_cur = SWAP_WORD(rl.rlim_cur); ss_rl.rlim_max = SWAP_WORD(rl.rlim_max); /* copy rlimit structure to target memory */ mem_bcopy(mem_fn, Write, /*rlimit*/regs_R[pid][5], &ss_rl, sizeof(struct ss_rlimit)); }#endif break;#if 0 case SS_SYS_getdirentries: /* FIXME: this is currently broken due to incompatabilities in disk directory formats */ { unsigned int i; char *buf; int base; buf = (char *)calloc(/* nbytes */regs_R[pid][6] + 1, sizeof(char)); if (!buf) fatal("out of memory in SYS_getdirentries"); /* copy in */ for (i=0; i</* nbytes */regs_R[pid][6]; i++) (*maf)(Read, /* buf */regs_R[pid][5]+i, (unsigned char *)&buf[i], 1); (*maf)(Read, /* basep */regs_R[pid][7], (unsigned char *)&base, 4); /*cc*/regs_R[pid][2] = getdirentries(/*fd*/regs_R[pid][4], buf, /*nbytes*/regs_R[pid][6], &base); if (regs_R[pid][2] != -1) regs_R[pid][7] = 0; else { regs_R[pid][2] = errno; regs_R[pid][7] = 1; } /* copy out */ for (i=0; i</* nbytes */regs_R[pid][6]; i++) (*maf)(Write, /* buf */regs_R[pid][5]+i, (unsigned char *)&buf[i], 1); (*maf)(Write, /* basep */regs_R[pid][7], (unsigned char *)&base, 4); free(buf); } break;#endif case SS_MP_ACQUIRE_LOCK: { int lock_id = regs_R[pid][4]; /* check if attempting to acquire another or same lock */ if (synchq[pid].synch_state == HOLDING_LOCK) fatal ("pid %d attempting to get lock %d" " but already has lock %d", pid, lock_id, synchq[pid].synch_var); else if (synchq[pid].synch_state != FREE) fatal ("pid %d attempting to get lock %d" " but already blocked on barrier or semaphore", pid, lock_id); /* check if at least one item in queue, which means lock is already held by a thread */ if (locks[lock_id]) { /* add ourselves to the end of the queue for this lock */ synchq[pid].next = locks[lock_id]->next; /* point to head */ locks[lock_id]->next = &synchq[pid]; /* add to tail */ locks[lock_id] = &synchq[pid]; /* update pointer to tail */ /* set synch state and var */ synchq[pid].synch_state = WAITING_FOR_LOCK; synchq[pid].synch_var = lock_id; /* mark as inactive until lock is acquired */ active[pid] = 0; debug ("pid %d must wait for lock %d", pid, lock_id); } else { /* we will get the lock; put ourselves at head of queue */ synchq[pid].next = &synchq[pid]; /* tail points to head */ locks[lock_id] = &synchq[pid]; /* update pointer to tail */ /* set synch state and var */ synchq[pid].synch_state = HOLDING_LOCK; synchq[pid].synch_var = lock_id; debug ("pid %d acquired lock %d", pid, lock_id); } } break; case SS_MP_RELEASE_LOCK: { int lock_id = regs_R[pid][4]; /* sanity check: we must be at the head of the queue (if lock is free, any thread can release) */ if (locks[lock_id] && locks[lock_id]->next->pid != pid) { fatal ("attempt to release lock held by another thread"); } /* set synch state of releasing thread*/ synchq[pid].synch_state = FREE; /* check if current lock holder is the only one in queue */ if (locks[lock_id]->next == locks[lock_id]) { locks[lock_id] = NULL; /* lock is now free */ debug ("pid %d released lock %d", pid, lock_id); } else /* at least one other thread waiting for lock */ { /* advance head of queue */ locks[lock_id]->next = locks[lock_id]->next->next; active[locks[lock_id]->next->pid] = 1; /* mark as active */ /* set synch state and var of thread being given the lock */ locks[lock_id]->next->synch_state = HOLDING_LOCK; locks[lock_id]->next->synch_var = lock_id; debug ("pid %d given lock %d by pid %d", locks[lock_id]->next->pid, lock_id, pid); } } break; case SS_MP_INIT_LOCK: { SS_ADDR_TYPE lock_ptr = regs_R[pid][4]; int i; int lock_id = num_used_locks++; if (num_used_locks > SANITY_LIMIT) fatal ("do you _really_ need %d locks ??\n", num_used_locks); if (num_used_locks > num_allocated_locks) { num_allocated_locks += LOCK_INCREMENT; locks = (SynchQNode **) realloc (locks, num_allocated_locks * sizeof (SynchQNode *)); /* initialize newly-allocated portion */ for (i = lock_id; i < num_allocated_locks; i++) { locks[i] = NULL; } } /* provide lock id to user program */ __MEM_WRITE_WORD(lock_ptr, lock_id); } break; case SS_MP_BARRIER: { int barrier_id = regs_R[pid][4]; /* note that for simplicity, all threads, include the last to arrive, are placed in the synch queue for the barrier */ /* check if at least one item already in queue */ if (barriers[barrier_id]) { /* add ourselves to the end of the queue for this barrier */ synchq[pid].next = barriers[barrier_id]->next;/* point to head*/ barriers[barrier_id]->next = &synchq[pid]; /* add to tail */ barriers[barrier_id] = &synchq[pid]; /* update pointer to tail*/ /* increment number of arrivals at barrier */ ++barrier_counts[barrier_id]; } else { /* first to arrive at this barrier */ synchq[pid].next = &synchq[pid]; /* tail points to head */ barriers[barrier_id] = &synchq[pid]; /* update pointer to tail */ barrier_counts[barrier_id] = 1; /* one arrival so far */ } /* set synch state and var */ synchq[pid].synch_state = BLOCKED_ON_BARRIER; synchq[pid].synch_var = barrier_id; /* mark as inactive until we know that all have arrived */ active[pid] = 0; debug ("pid %d arrived at barrier %d", pid, barrier_id); /* now check if all have arrived at barrier */ if (regs_R[pid][5] == barrier_counts[barrier_id]) { SynchQNode *p; /* traverse the queue and mark _all_ threads as active (including the last arrival) */ p = barriers[barrier_id]->next; /* get head of list */ do { active[p->pid] = 1; /* set synch state and var */ synchq[p->pid].synch_state = FREE; debug ("pid %d leaving barrier %d", p->pid, barrier_id); p = p->next; } while (p != barriers[barrier_id]->next); /* back at head? */ /* reset count to zero */ barrier_counts[barrier_id] = 0; /* last step is to set queue tail pointer to null */ barriers[barrier_id] = NULL; } } break; case SS_MP_INIT_BARRIER: { SS_ADDR_TYPE barrier_ptr = regs_R[pid][4]; int i; int barrier_id = num_used_barriers++; if (num_used_barriers > SANITY_LIMIT) fatal ("do you _really_ need %d barriers ??\n", num_used_barriers); if (num_used_barriers > num_allocated_barriers) { num_allocated_barriers += BARRIER_INCREMENT; barriers = (SynchQNode **) realloc (barriers, num_allocated_barriers * sizeof (SynchQNode *)); barrier_counts = (int *) realloc (barrier_counts, num_allocated_barriers * sizeof (int)); /* initialize newly-allocated portions */ for (i = barrier_id; i < num_allocated_barriers; i++) { barriers[i] = NULL; barrier_counts[i] = 0; } } /* provide barrier id to user program */ __MEM_WRITE_WORD(barrier_ptr, barrier_id); } break; case SS_MP_SEMA_WAIT: { int sema_id = regs_R[pid][4]; /* if we decrement the count and it is negative, we must block */ if (--sema_counts[sema_id] < 0) { /* mark as inactive until matching signal unblocks it */ active[pid] = 0; debug ("pid %d blocked on semaphore %d", pid, sema_id); /* set synch state and var */ synchq[pid].synch_state = BLOCKED_ON_SEMAPHORE; synchq[pid].synch_var = sema_id; /* check if at least one item in queue, which means at least one thread is already blocked on semaphore */ if (semaphores[sema_id]) { /* add ourselves to end of queue for this semaphore */ synchq[pid].next = semaphores[sema_id]->next; semaphores[sema_id]->next = &synchq[pid]; semaphores[sema_id] = &synchq[pid]; } else { /* first to block; put ourselves at head of queue */ synchq[pid].next = &synchq[pid]; semaphores[sema_id] = &synchq[pid]; } } else debug ("pid %d did not block on semaphore %d", pid, sema_id); } break; case SS_MP_SEMA_SIGNAL: { int sema_id = regs_R[pid][4]; /* increment count; if result is zero or negative, there is at least one thread blocked, so unblock it */ if (++sema_counts[sema_id] <= 0) { /* sanity check: there must be at least one blocked thread if the count is <= 0 */ if (semaphores[sema_id] == NULL) { fatal ("semaphore signal expected a blocked thread"); } /* make thread at head of queue active */ active[semaphores[sema_id]->next->pid] = 1; /* set synch state of newly-reactivated thread */ semaphores[sema_id]->next->synch_state = FREE; debug ("pid %d unblocked on semaphore %d by pid %d", semaphores[sema_id]->next->pid, sema_id, pid); /* check if queue has only one item */ if (semaphores[sema_id]->next == semaphores[sema_id]) { semaphores[sema_id] = NULL; /* queue is now empty */ } else /* at least one other thread was blocked */ { /* advance head of queue */ semaphores[sema_id]->next = semaphores[sema_id]->next->next; } } } break; case SS_MP_INIT_SEMA: { SS_ADDR_TYPE sema_ptr = regs_R[pid][4]; int i; int sema_id = num_used_semaphores++; if (num_used_semaphores > SANITY_LIMIT) fatal ("do you _really_ need %d semaphores ??\n", num_used_semaphores); if (num_used_semaphores > num_allocated_semaphores) { num_allocated_semaphores += SEMAPHORE_INCREMENT; semaphores = (SynchQNode **) realloc (semaphores, num_allocated_semaphores*sizeof(SynchQNode *)); sema_counts = (int *) realloc (sema_counts, num_allocated_semaphores * sizeof (int)); /* initialize newly-allocated portions */ for (i = sema_id; i < num_allocated_semaphores; i++) { semaphores[i] = NULL; sema_counts[i] = 0; } } /* set initial semaphore count value */ sema_counts[sema_id] = regs_R[pid][5]; /* provide semaphore id to user program */ __MEM_WRITE_WORD(sema_ptr, sema_id); } break; case SS_MP_THREAD_ID: regs_R[pid][7] = 0; regs_R[pid][2] = pid; break; case SS_MP_CREATE_THREAD: { CreateNewProcess (pid, /* func_ptr */ (void (*)()) regs_R[pid][4], /* wrapper */ (void (*)()) regs_R[pid][5]); regs_R[pid][7] = 0; regs_R[pid][2] = 0; } break; case SS_MP_EXIT_THREAD: { if (pid == 0) panic("ERROR: main thread should not call exit_thread()\n"); ++num_terminated_processes; active[pid] = 0; /* mark this one as inactive */ if (num_terminated_processes == num_created_processes) { /* exit jumps to the target set in main() */ longjmp(sim_exit_buf, /* exitcode + fudge */regs_R[pid][4]+1); } /* else we must wait until last thread finishes (this one has been marked inactive, so when we return to the main simulation loop, no further instructions will be fetched for this thread) */ } break; default: panic("invalid/unimplemented system call encountered, code %d", syscode); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -