Beispiel #1
0
/*!	Searches a free slot in the FD table of the provided I/O context, and
	inserts the specified descriptor into it.
*/
int
new_fd_etc(struct io_context* context, struct file_descriptor* descriptor,
	int firstIndex)
{
	int fd = -1;
	uint32 i;

	mutex_lock(&context->io_mutex);

	for (i = firstIndex; i < context->table_size; i++) {
		if (!context->fds[i]) {
			fd = i;
			break;
		}
	}
	if (fd < 0) {
		fd = B_NO_MORE_FDS;
		goto err;
	}

	TFD(NewFD(context, fd, descriptor));

	context->fds[fd] = descriptor;
	context->num_used_fds++;
	atomic_add(&descriptor->open_count, 1);

err:
	mutex_unlock(&context->io_mutex);

	return fd;
}
Beispiel #2
0
/*!	POSIX says this should be the same as:
		close(newfd);
		fcntl(oldfd, F_DUPFD, newfd);

	We do dup2() directly to be thread-safe.
*/
static int
dup2_fd(int oldfd, int newfd, bool kernel)
{
	struct file_descriptor* evicted = NULL;
	struct io_context* context;

	TRACE(("dup2_fd: ofd = %d, nfd = %d\n", oldfd, newfd));

	// quick check
	if (oldfd < 0 || newfd < 0)
		return B_FILE_ERROR;

	// Get current I/O context and lock it
	context = get_current_io_context(kernel);
	mutex_lock(&context->io_mutex);

	// Check if the fds are valid (mutex must be locked because
	// the table size could be changed)
	if ((uint32)oldfd >= context->table_size
		|| (uint32)newfd >= context->table_size
		|| context->fds[oldfd] == NULL
		|| (context->fds[oldfd]->open_mode & O_DISCONNECTED) != 0) {
		mutex_unlock(&context->io_mutex);
		return B_FILE_ERROR;
	}

	// Check for identity, note that it cannot be made above
	// because we always want to return an error on invalid
	// handles
	select_info* selectInfos = NULL;
	if (oldfd != newfd) {
		// Now do the work
		TFD(Dup2FD(context, oldfd, newfd));

		evicted = context->fds[newfd];
		selectInfos = context->select_infos[newfd];
		context->select_infos[newfd] = NULL;
		atomic_add(&context->fds[oldfd]->ref_count, 1);
		atomic_add(&context->fds[oldfd]->open_count, 1);
		context->fds[newfd] = context->fds[oldfd];

		if (evicted == NULL)
			context->num_used_fds++;
	}

	fd_set_close_on_exec(context, newfd, false);

	mutex_unlock(&context->io_mutex);

	// Say bye bye to the evicted fd
	if (evicted) {
		deselect_select_infos(evicted, selectInfos, true);
		close_fd(evicted);
		put_fd(evicted);
	}

	return newfd;
}
Beispiel #3
0
static struct file_descriptor*
get_fd_locked(struct io_context* context, int fd)
{
	if (fd < 0 || (uint32)fd >= context->table_size)
		return NULL;

	struct file_descriptor* descriptor = context->fds[fd];

	if (descriptor != NULL) {
		TFD(GetFD(context, fd, descriptor));
		inc_fd_ref_count(descriptor);
	}

	return descriptor;
}
Beispiel #4
0
static struct file_descriptor*
get_fd_locked(struct io_context* context, int fd)
{
	if (fd < 0 || (uint32)fd >= context->table_size)
		return NULL;

	struct file_descriptor* descriptor = context->fds[fd];

	if (descriptor != NULL) {
		// Disconnected descriptors cannot be accessed anymore
		if (descriptor->open_mode & O_DISCONNECTED)
			descriptor = NULL;
		else {
			TFD(GetFD(context, fd, descriptor));
			inc_fd_ref_count(descriptor);
		}
	}

	return descriptor;
}
Beispiel #5
0
/*!	Reduces the descriptor's reference counter, and frees all resources
	when it's no longer used.
*/
void
put_fd(struct file_descriptor* descriptor)
{
	int32 previous = atomic_add(&descriptor->ref_count, -1);

	TFD(PutFD(descriptor));

	TRACE(("put_fd(descriptor = %p [ref = %ld, cookie = %p])\n",
		descriptor, descriptor->ref_count, descriptor->cookie));

	// free the descriptor if we don't need it anymore
	if (previous == 1) {
		// free the underlying object
		if (descriptor->ops != NULL && descriptor->ops->fd_free != NULL)
			descriptor->ops->fd_free(descriptor);

		free(descriptor);
	} else if ((descriptor->open_mode & O_DISCONNECTED) != 0
		&& previous - 1 == descriptor->open_count
		&& descriptor->ops != NULL) {
		// the descriptor has been disconnected - it cannot
		// be accessed anymore, let's close it (no one is
		// currently accessing this descriptor)

		if (descriptor->ops->fd_close)
			descriptor->ops->fd_close(descriptor);
		if (descriptor->ops->fd_free)
			descriptor->ops->fd_free(descriptor);

		// prevent this descriptor from being closed/freed again
		descriptor->open_count = -1;
		descriptor->ref_count = -1;
		descriptor->ops = NULL;
		descriptor->u.vnode = NULL;

		// the file descriptor is kept intact, so that it's not
		// reused until someone explicetly closes it
	}
}
Beispiel #6
0
/*!	Removes the file descriptor from the specified slot.
*/
static struct file_descriptor*
remove_fd(struct io_context* context, int fd)
{
	struct file_descriptor* descriptor = NULL;

	if (fd < 0)
		return NULL;

	mutex_lock(&context->io_mutex);

	if ((uint32)fd < context->table_size)
		descriptor = context->fds[fd];

	select_info* selectInfos = NULL;
	bool disconnected = false;

	if (descriptor != NULL)	{
		// fd is valid
		TFD(RemoveFD(context, fd, descriptor));

		context->fds[fd] = NULL;
		fd_set_close_on_exec(context, fd, false);
		context->num_used_fds--;

		selectInfos = context->select_infos[fd];
		context->select_infos[fd] = NULL;

		disconnected = (descriptor->open_mode & O_DISCONNECTED);
	}

	mutex_unlock(&context->io_mutex);

	if (selectInfos != NULL)
		deselect_select_infos(descriptor, selectInfos, true);

	return disconnected ? NULL : descriptor;
}