コード例 #1
0
ファイル: sem.c プロジェクト: alexandermerritt/dragonfly
static int
put_shmdata(int id) {
	struct shm_data *data;
	int ret = -1;

	SYSV_MUTEX_LOCK(&lock_resources);
	data = _hash_lookup(shmres, id);
	if (!data) {
		sysv_print_err("something wrong put_shmdata\n");
		goto done; /* It should not reach here. */
	}

	data->used--;
	if (data->used == 0 && data->removed) {
		sysv_print("really remove the sem\n");
		SYSV_MUTEX_UNLOCK(&lock_resources);
		/* OBS: Even if the shmctl fails (the thread doesn't
		 * have IPC_M permissions), all structures associated
		 * with it will be removed in the current process.*/
		sysvipc_shmdt(data->internal);
		semundo_clear(id, -1);
		if (data->removed == SEG_ALREADY_REMOVED)
			return 1; /* The semaphore was removed
			by another process so there is nothing else
			we must do. */
		/* Else inform the daemon that the segment is removed. */
		return (sysvipc_shmctl(id, IPC_RMID, NULL));
	}

	ret = 0;
done:
	SYSV_MUTEX_UNLOCK(&lock_resources);
	return (ret);
}
コード例 #2
0
/* Handle a shmdt() request. */
int
handle_shmdt(pid_t pid, int shmid) {
	struct shmid_ds *shmseg;
	int segnum;
	struct shm_handle *handle;
	struct pid_attached *pidatt;
	struct id_attached *idatt;
	struct client *cl;

	sysvd_print("shmdt pid %d shmid %d\n", pid, shmid);
	/*if (!jail_sysvipc_allowed && td->td_cmsgcred->cr_prison != NULL)
	  return (ENOSYS);
	*/

	segnum = IPCID_TO_IX(shmid);
	shmseg = &shmsegs[segnum];
	handle = shmseg->shm_internal;

	/* Check if pid is attached. */
	LIST_FOREACH(pidatt, &handle->attached_list, link)
		if (pidatt->pid == pid)
			break;
	if (!pidatt) {
		sysvd_print_err("process %d is not attached to %d (1)\n",
				pid, shmid);
		return (EINVAL);
	}
	LIST_REMOVE(pidatt, link);

	/* Remove the segment from the list of attached segments of the pid.*/
	cl = _hash_lookup(clientshash, pid);
	LIST_FOREACH(idatt, &cl->ids_attached, link)
		if (idatt->shmid == shmid)
			break;
	if (!idatt) {
		sysvd_print_err("process %d is not attached to %d (2)\n",
				pid, shmid);
		return (EINVAL);
	}
	LIST_REMOVE(idatt, link);

	shmseg->shm_dtime = time(NULL);

	/* If no other process attaced remove the segment. */
	if ((--shmseg->shm_nattch <= 0) &&
			(shmseg->shm_perm.mode & SHMSEG_REMOVED)) {
		shm_deallocate_segment(segnum);
		shm_last_free = segnum;
	}

	return (0);
}
コード例 #3
0
/* Install for the client the file corresponding to fd. */
static int
install_fd_client(pid_t pid, int fd) {
	int ret;
	struct client *cl = _hash_lookup(clientshash, pid);
	if (!cl) {
		sysvd_print_err("no client entry for pid = %d\n", pid);
		return (-1);
	}

	ret = send_fd(cl->sock, fd);
	if (ret < 0) {
		sysvd_print_err("can not send fd to client %d\n", pid);
		return (-1);
	}

	return (0);
}
コード例 #4
0
/* add into hash table without checking for repeats */
int hash_remove(T_HashTable *H,T_HashTableEl *E, int hint)
{
  T_HashTableEl *E2;

  if (hint >=0 && hint < H->size &&
      H->entries[hint] == E){
    H->inuse--;
    H->entries[hint] = &deleted;
    return 0;
  }

  if(_hash_lookup(H, E, &E2, &hint, 1)) {
	  fprintf(stderr, "Removing non-existent entry\n");
	  exit(1);
	  return -1;
  }
  H->inuse--;
  H->entries[hint] = &deleted;
  return 0;
}
コード例 #5
0
int hash_lookup(T_HashTable *H,T_HashTableEl *E, T_HashTableEl **E2,
		int *hint)
{
	return _hash_lookup(H, E, E2, hint, 0);
}
コード例 #6
0
ファイル: sem.c プロジェクト: alexandermerritt/dragonfly
/*
 * Adjust a particular entry for a particular proc
 */
static int
semundo_adjust(int semid, int semnum, int adjval)
{
	struct undo *sunptr;
	int i;
	int error = 0;
	size_t size;
	int undoid;
	void *addr;
	struct shm_data *data;

	sysv_print("semundo adjust\n");
	if (!adjval)
		goto done;

	SYSV_MUTEX_LOCK(&lock_undo);
	if (!undos) {
		sysv_print("get undo segment\n");
		undoid = _shmget(IPC_PRIVATE, PAGE_SIZE, IPC_CREAT | IPC_EXCL | 0600,
				UNDOGET);
		if (undoid == -1) {
			sysv_print_err("no undo segment\n");
			return (-1);
		}

		addr = sysvipc_shmat(undoid, NULL, 0);
		if (!addr) {
			sysv_print_err("can not map undo segment\n");
			sysvipc_shmctl(undoid, IPC_RMID, NULL);
			return (-1);
		}

		undos = (struct sem_undo *)addr;
		undos->un_pages = 1;
		undos->un_cnt = 0;
	}

	/*
	 * Look for the requested entry and adjust it (delete if adjval becomes
	 * 0).
	 */
	sunptr = &undos->un_ent[0];
	for (i = 0; i < undos->un_cnt; i++, sunptr++) {
		if (sunptr->un_id != semid && sunptr->un_num != semnum)
			continue;
		sunptr->un_adjval += adjval;
		if (sunptr->un_adjval == 0) {
			undos->un_cnt--;
			if (i < undos->un_cnt)
				undos->un_ent[i] = undos->un_ent[undos->un_cnt];
		}
		goto done;
	}

	/* Didn't find the right entry - create it */
	size = sizeof(struct sem_undo) + (undos->un_cnt + 1) *
		sizeof(struct sem_undo);
	if (size > (unsigned int)(undos->un_pages * PAGE_SIZE)) {
		sysv_print("need more undo space\n");
		sysvipc_shmdt(undos);
		undos->un_pages++;

		SYSV_MUTEX_LOCK(&lock_resources);
		data = _hash_lookup(shmaddrs, (u_long)undos);
		SYSV_MUTEX_UNLOCK(&lock_resources);

		/* It is not necessary any lock on "size" because it is used
		 * only by shmat and shmdt.
		 * shmat for undoid is called only from this function and it
		 * is protected by undo_lock.
		 * shmdt for undoid is not called anywhere because the segment
		 * is destroyed by the daemon when the client dies.
		 */
		data->size = undos->un_pages * PAGE_SIZE;
		undos = sysvipc_shmat(data->shmid, NULL, 0);
	}

	sunptr = &undos->un_ent[undos->un_cnt];
	undos->un_cnt++;
	sunptr->un_adjval = adjval;
	sunptr->un_id = semid;
	sunptr->un_num = semnum;
	//if (suptr->un_cnt == seminfo.semume) TODO move it in daemon
	/*} else {
	  error = EINVAL; //se face prin notificare
	  }*/
done:
	SYSV_MUTEX_UNLOCK(&lock_undo);

	sysv_print("semundo adjust end\n");
	return (error);
}
コード例 #7
0
/* Handle a shmat() request. */
int
handle_shmat(pid_t pid, struct shmat_msg *shmat_msg,
		struct cmsgcred *cred ) {
	int error;
	int fd;
	struct shmid_ds *shmseg;
	struct pid_attached *pidatt;
	struct shm_handle *handle;
	size_t new_size = shmat_msg->size;
	struct client *cl;
	struct id_attached *idatt;

	/*if (!jail_sysvipc_allowed && td->td_cmsgcred->cr_prison != NULL)
	  return (ENOSYS);

again:*/
	shmseg = shm_find_segment_by_shmid(shmat_msg->shmid);
	if (shmseg == NULL) {
		sysvd_print_err("shmat error: segment was not found\n");
		error = EINVAL;
		goto done;
	}
	error = ipcperm(cred, &shmseg->shm_perm, 
			(shmat_msg->shmflg & SHM_RDONLY) ? IPC_R : IPC_R|IPC_W);
	if (error)
		goto done;

	handle = shmseg->shm_internal;

	if (shmat_msg->size > shmseg->shm_segsz) {
		if (handle->type != UNDOGET) {
			error = EINVAL;
			goto done;
		}

		fd = ((struct shm_handle*)shmseg->shm_internal)->fd;
		ftruncate(fd, round_page(new_size));
		shmseg->shm_segsz = new_size;
	}

	shmseg->shm_lpid = pid;
	shmseg->shm_atime = time(NULL);

	if (handle->type != UNDOGET)
		shmseg->shm_nattch++;
	else
		shmseg->shm_nattch = 1; /* Only a process calls shmat and
		only once. If it does it for more than once that is because
		it called exec() and reinitialized the undo segment. */

	/* Insert the pid in the segment list of attaced pids.
	 * The list is checked in handle_shmdt so that only
	 * attached pids can dettached from this segment.
	 */
	sysvd_print("nattch = %d pid = %d\n",
			shmseg->shm_nattch, pid);

	pidatt = malloc(sizeof(*pidatt));
	pidatt->pid = pid;
	LIST_INSERT_HEAD(&handle->attached_list, pidatt, link);

	/* Add the segment at the list of attached segments of the client.
	 * It is used when the process finishes its execution. The daemon
	 * walks through the list to dettach the segments.
	 */
	idatt = malloc(sizeof(*idatt));
	idatt->shmid = shmat_msg->shmid;
	cl = _hash_lookup(clientshash, pid);
	LIST_INSERT_HEAD(&cl->ids_attached, idatt, link);

	return (0);
done:
	return (error);
}
コード例 #8
0
/* Create a shared memory segment and return the id. */
static int
shmget_allocate_segment(pid_t pid, struct shmget_msg *shmget_msg,
		int mode, struct cmsgcred *cred)
{
	int i, segnum, shmid;
	size_t size;
	struct shmid_ds *shmseg;
	struct shm_handle *handle;
#if 0
	/* It is possible after a process calls exec().
	 * We don't create another segment but return the old one
	 * with all information.
	 * This segment is destroyed only when process dies.
	 * */
	if (shmget_msg->type == UNDOGET) {
		struct client *cl= _hash_lookup(clientshash, pid);
		if (cl->undoid != -1)
			return cl->undoid;
	}
#endif
	if ((long)shmget_msg->size < shminfo.shmmin)
			//|| (long)shmget_msg->size > shminfo.shmmax)
			/* There is no need to check the max limit,
			 * the operating system do this for us.
			 */
		return (-EINVAL);
	if (shm_nused >= shminfo.shmmni) /* any shmids left? */
		return (-ENOSPC);

	/* Compute the size of the segment. */
	size = round_page(shmget_msg->size);

	/* Find a free entry in the shmsegs vector. */
	if (shm_last_free < 0) {
		//	shmrealloc();	/* maybe expand the shmsegs[] array */
		for (i = 0; i < shmalloced; i++) {
			if (shmsegs[i].shm_perm.mode & SHMSEG_FREE)
				break;
		}
		if (i == shmalloced) {
			sysvd_print("i == shmalloced\n");
			return (-ENOSPC);
		}
		segnum = i;
	} else  {
		segnum = shm_last_free;
		shm_last_free = -1;
	}
	shmseg = &shmsegs[segnum];
	/*
	 * In case we sleep in malloc(), mark the segment present but deleted
	 * so that noone else tries to create the same key.
	 */
	shmseg->shm_perm.mode = SHMSEG_ALLOCATED | SHMSEG_REMOVED;
	shmseg->shm_perm.key = shmget_msg->key;
	shmseg->shm_perm.seq = (shmseg->shm_perm.seq + 1) & 0x7fff;

	/* Create the file for the shared memory segment. */
	handle = shmseg->shm_internal = malloc(sizeof(struct shm_handle));
	handle->type = shmget_msg->type;
	handle->fd = create_sysv_file(shmget_msg, size, shmseg);
	if (handle->fd == -1) {
		free(handle);
		handle = NULL;
		shmseg->shm_perm.mode = SHMSEG_FREE;
		shm_last_free = segnum;
		errno = -ENFILE;
		return (-1);
	}

	LIST_INIT(&handle->attached_list);

	if (handle->fd < 0) {
		free(shmseg->shm_internal);
		shmseg->shm_internal = NULL;
		shm_last_free = segnum;
		shmseg->shm_perm.mode = SHMSEG_FREE;
		return (-errno);
	}

	/* Get the id. */
	shmid = IXSEQ_TO_IPCID(segnum, shmseg->shm_perm);

	shmseg->shm_perm.cuid = shmseg->shm_perm.uid = cred->cmcred_euid;
	shmseg->shm_perm.cgid = shmseg->shm_perm.gid = cred->cmcred_gid;
	shmseg->shm_perm.mode = (shmseg->shm_perm.mode & SHMSEG_WANTED) |
		(mode & ACCESSPERMS) | SHMSEG_ALLOCATED;

	shmseg->shm_cpid = pid;
	shmseg->shm_lpid = shmseg->shm_nattch = 0;
	shmseg->shm_atime = shmseg->shm_dtime = 0;
	shmseg->shm_ctime = time(NULL);

	shmseg->shm_segsz = shmget_msg->size;
	shm_committed += btoc(size);
	shm_nused++;

	if (shmseg->shm_perm.mode & SHMSEG_WANTED) {
		/*
		 * Somebody else wanted this key while we were asleep.  Wake
		 * them up now.
		 */
		shmseg->shm_perm.mode &= ~SHMSEG_WANTED;
		//TODO multithreading
		//wakeup((caddr_t)shmseg);
	}
	shmseg->shm_perm.mode &= ~SHMSEG_REMOVED;

	if (shmget_msg->type == UNDOGET) {
		/* The file is used by daemon when clients terminates
		 * and sem_undo resources must be cleaned.
		 */
		struct client *cl= _hash_lookup(clientshash, pid);
		cl->undoid = shmid;
	}

	return (shmid);
}