void io_close_port(object port) { if (!is_port_closed(port)) { fclose(port_implementation(port)); set_port_closed(port); } }
status_t _get_next_port_info(team_id team, int32* _cookie, struct port_info* info, size_t size) { TRACE(("get_next_port_info(team = %ld)\n", team)); if (info == NULL || size != sizeof(port_info) || _cookie == NULL || team < B_OK) return B_BAD_VALUE; if (!sPortsActive) return B_BAD_PORT_ID; int32 slot = *_cookie; if (slot >= sMaxPorts) return B_BAD_PORT_ID; if (team == B_CURRENT_TEAM) team = team_get_current_team_id(); info->port = -1; // used as found flag while (slot < sMaxPorts) { MutexLocker locker(sPorts[slot].lock); if (sPorts[slot].id != -1 && !is_port_closed(slot) && sPorts[slot].owner == team) { // found one! fill_port_info(&sPorts[slot], info, size); slot++; break; } slot++; } if (info->port == -1) return B_BAD_PORT_ID; *_cookie = slot; return B_OK; }
status_t select_port(int32 id, struct select_info* info, bool kernel) { if (id < 0) return B_BAD_PORT_ID; int32 slot = id % sMaxPorts; MutexLocker locker(sPorts[slot].lock); if (sPorts[slot].id != id || is_port_closed(slot)) return B_BAD_PORT_ID; if (!kernel && sPorts[slot].owner == team_get_kernel_team_id()) { // kernel port, but call from userland return B_NOT_ALLOWED; } info->selected_events &= B_EVENT_READ | B_EVENT_WRITE | B_EVENT_INVALID; if (info->selected_events != 0) { uint16 events = 0; info->next = sPorts[slot].select_infos; sPorts[slot].select_infos = info; // check for events if ((info->selected_events & B_EVENT_READ) != 0 && !sPorts[slot].messages.IsEmpty()) { events |= B_EVENT_READ; } if (sPorts[slot].write_count > 0) events |= B_EVENT_WRITE; if (events != 0) notify_select_events(info, events); } return B_OK; }
status_t writev_port_etc(port_id id, int32 msgCode, const iovec* msgVecs, size_t vecCount, size_t bufferSize, uint32 flags, bigtime_t timeout) { if (!sPortsActive || id < 0) return B_BAD_PORT_ID; if (bufferSize > PORT_MAX_MESSAGE_SIZE) return B_BAD_VALUE; // mask irrelevant flags (for acquire_sem() usage) flags &= B_CAN_INTERRUPT | B_KILL_CAN_INTERRUPT | B_RELATIVE_TIMEOUT | B_ABSOLUTE_TIMEOUT; if ((flags & B_RELATIVE_TIMEOUT) != 0 && timeout != B_INFINITE_TIMEOUT && timeout > 0) { // Make the timeout absolute, since we have more than one step where // we might have to wait flags = (flags & ~B_RELATIVE_TIMEOUT) | B_ABSOLUTE_TIMEOUT; timeout += system_time(); } bool userCopy = (flags & PORT_FLAG_USE_USER_MEMCPY) > 0; int32 slot = id % sMaxPorts; status_t status; port_message* message = NULL; MutexLocker locker(sPorts[slot].lock); if (sPorts[slot].id != id) { TRACE(("write_port_etc: invalid port_id %ld\n", id)); return B_BAD_PORT_ID; } if (is_port_closed(slot)) { TRACE(("write_port_etc: port %ld closed\n", id)); return B_BAD_PORT_ID; } if (sPorts[slot].write_count <= 0) { if ((flags & B_RELATIVE_TIMEOUT) != 0 && timeout <= 0) return B_WOULD_BLOCK; sPorts[slot].write_count--; // We need to block in order to wait for a free message slot ConditionVariableEntry entry; sPorts[slot].write_condition.Add(&entry); locker.Unlock(); status = entry.Wait(flags, timeout); locker.Lock(); if (sPorts[slot].id != id || is_port_closed(slot)) { // the port is no longer there T(Write(sPorts[slot], 0, 0, B_BAD_PORT_ID)); return B_BAD_PORT_ID; } if (status != B_OK) goto error; } else sPorts[slot].write_count--; status = get_port_message(msgCode, bufferSize, flags, timeout, &message); if (status != B_OK) goto error; // sender credentials message->sender = geteuid(); message->sender_group = getegid(); message->sender_team = team_get_current_team_id(); if (bufferSize > 0) { uint32 i; if (userCopy) { // copy from user memory for (i = 0; i < vecCount; i++) { size_t bytes = msgVecs[i].iov_len; if (bytes > bufferSize) bytes = bufferSize; status_t status = user_memcpy(message->buffer, msgVecs[i].iov_base, bytes); if (status != B_OK) { put_port_message(message); goto error; } bufferSize -= bytes; if (bufferSize == 0) break; } } else { // copy from kernel memory for (i = 0; i < vecCount; i++) { size_t bytes = msgVecs[i].iov_len; if (bytes > bufferSize) bytes = bufferSize; memcpy(message->buffer, msgVecs[i].iov_base, bytes); bufferSize -= bytes; if (bufferSize == 0) break; } } } sPorts[slot].messages.Add(message); sPorts[slot].read_count++; T(Write(sPorts[slot], message->code, message->size, B_OK)); notify_port_select_events(slot, B_EVENT_READ); sPorts[slot].read_condition.NotifyOne(); return B_OK; error: // Give up our slot in the queue again, and let someone else // try and fail T(Write(sPorts[slot], 0, 0, status)); sPorts[slot].write_count++; notify_port_select_events(slot, B_EVENT_WRITE); sPorts[slot].write_condition.NotifyOne(); return status; }
ssize_t read_port_etc(port_id id, int32* _code, void* buffer, size_t bufferSize, uint32 flags, bigtime_t timeout) { if (!sPortsActive || id < 0) return B_BAD_PORT_ID; if ((buffer == NULL && bufferSize > 0) || timeout < 0) return B_BAD_VALUE; bool userCopy = (flags & PORT_FLAG_USE_USER_MEMCPY) != 0; bool peekOnly = !userCopy && (flags & B_PEEK_PORT_MESSAGE) != 0; // TODO: we could allow peeking for user apps now flags &= B_CAN_INTERRUPT | B_KILL_CAN_INTERRUPT | B_RELATIVE_TIMEOUT | B_ABSOLUTE_TIMEOUT; int32 slot = id % sMaxPorts; MutexLocker locker(sPorts[slot].lock); if (sPorts[slot].id != id || (is_port_closed(slot) && sPorts[slot].messages.IsEmpty())) { T(Read(sPorts[slot], 0, B_BAD_PORT_ID)); TRACE(("read_port_etc(): %s port %ld\n", sPorts[slot].id == id ? "closed" : "invalid", id)); return B_BAD_PORT_ID; } while (sPorts[slot].read_count == 0) { if ((flags & B_RELATIVE_TIMEOUT) != 0 && timeout <= 0) return B_WOULD_BLOCK; // We need to wait for a message to appear ConditionVariableEntry entry; sPorts[slot].read_condition.Add(&entry); locker.Unlock(); // block if no message, or, if B_TIMEOUT flag set, block with timeout status_t status = entry.Wait(flags, timeout); locker.Lock(); if (sPorts[slot].id != id || (is_port_closed(slot) && sPorts[slot].messages.IsEmpty())) { // the port is no longer there T(Read(sPorts[slot], 0, B_BAD_PORT_ID)); return B_BAD_PORT_ID; } if (status != B_OK) { T(Read(sPorts[slot], 0, status)); return status; } } // determine tail & get the length of the message port_message* message = sPorts[slot].messages.Head(); if (message == NULL) { panic("port %ld: no messages found\n", sPorts[slot].id); return B_ERROR; } if (peekOnly) { size_t size = copy_port_message(message, _code, buffer, bufferSize, userCopy); T(Read(sPorts[slot], message->code, size)); sPorts[slot].read_condition.NotifyOne(); // we only peeked, but didn't grab the message return size; } sPorts[slot].messages.RemoveHead(); sPorts[slot].total_count++; sPorts[slot].write_count++; sPorts[slot].read_count--; notify_port_select_events(slot, B_EVENT_WRITE); sPorts[slot].write_condition.NotifyOne(); // make one spot in queue available again for write locker.Unlock(); size_t size = copy_port_message(message, _code, buffer, bufferSize, userCopy); T(Read(sPorts[slot], message->code, size)); put_port_message(message); return size; }
status_t _get_port_message_info_etc(port_id id, port_message_info* info, size_t infoSize, uint32 flags, bigtime_t timeout) { if (info == NULL || infoSize != sizeof(port_message_info)) return B_BAD_VALUE; if (!sPortsActive || id < 0) return B_BAD_PORT_ID; flags &= B_CAN_INTERRUPT | B_KILL_CAN_INTERRUPT | B_RELATIVE_TIMEOUT | B_ABSOLUTE_TIMEOUT; int32 slot = id % sMaxPorts; MutexLocker locker(sPorts[slot].lock); if (sPorts[slot].id != id || (is_port_closed(slot) && sPorts[slot].messages.IsEmpty())) { T(Info(sPorts[slot], 0, B_BAD_PORT_ID)); TRACE(("_get_port_message_info_etc(): %s port %ld\n", sPorts[slot].id == id ? "closed" : "invalid", id)); return B_BAD_PORT_ID; } while (sPorts[slot].read_count == 0) { // We need to wait for a message to appear if ((flags & B_RELATIVE_TIMEOUT) != 0 && timeout <= 0) return B_WOULD_BLOCK; ConditionVariableEntry entry; sPorts[slot].read_condition.Add(&entry); locker.Unlock(); // block if no message, or, if B_TIMEOUT flag set, block with timeout status_t status = entry.Wait(flags, timeout); if (status != B_OK) { T(Info(sPorts[slot], 0, status)); return status; } locker.Lock(); if (sPorts[slot].id != id || (is_port_closed(slot) && sPorts[slot].messages.IsEmpty())) { // the port is no longer there T(Info(sPorts[slot], 0, B_BAD_PORT_ID)); return B_BAD_PORT_ID; } } // determine tail & get the length of the message port_message* message = sPorts[slot].messages.Head(); if (message == NULL) { panic("port %ld: no messages found\n", sPorts[slot].id); return B_ERROR; } info->size = message->size; info->sender = message->sender; info->sender_group = message->sender_group; info->sender_team = message->sender_team; T(Info(sPorts[slot], message->code, B_OK)); // notify next one, as we haven't read from the port sPorts[slot].read_condition.NotifyOne(); return B_OK; }