Skip to content

Commit

Permalink
kern: SvcConnectToNamedPort
Browse files Browse the repository at this point in the history
  • Loading branch information
SciresM committed Jul 10, 2020
1 parent a2eb93f commit 7400a8f
Show file tree
Hide file tree
Showing 15 changed files with 376 additions and 15 deletions.
34 changes: 28 additions & 6 deletions libraries/libmesosphere/include/mesosphere/kern_k_auto_object.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -177,10 +177,12 @@ namespace ams::kern {
}
};

template<typename T>
template<typename T> requires std::derived_from<T, KAutoObject>
class KScopedAutoObject {
static_assert(std::is_base_of<KAutoObject, T>::value);
NON_COPYABLE(KScopedAutoObject);
private:
template<typename U>
friend class KScopedAutoObject;
private:
T *obj;
private:
Expand All @@ -202,12 +204,32 @@ namespace ams::kern {
this->obj = nullptr;
}

constexpr ALWAYS_INLINE KScopedAutoObject(KScopedAutoObject &&rhs) {
this->obj = rhs.obj;
rhs.obj = nullptr;
template<typename U>
constexpr ALWAYS_INLINE KScopedAutoObject(KScopedAutoObject<U> &&rhs) {
if constexpr (std::same_as<T, U>) {
this->obj = rhs.obj;
rhs.obj = nullptr;
} else {
T *derived = rhs.obj->template DynamicCast<T *>();
if (derived == nullptr) {
rhs.obj->Close();
}

this->obj = derived;
rhs.obj = nullptr;
}
}

constexpr ALWAYS_INLINE KScopedAutoObject &operator=(KScopedAutoObject &&rhs) {
template<typename U>
constexpr ALWAYS_INLINE KScopedAutoObject &operator=(KScopedAutoObject<U> &&rhs) {
if constexpr (!std::same_as<T, U>) {
T *derived = rhs.obj->template DynamicCast<T *>();
if (derived == nullptr) {
rhs.obj->Close();
}
rhs.obj = nullptr;
}

rhs.Swap(*this);
return *this;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@
namespace ams::kern {

class KPort;
class KSession;
class KClientSession;
class KLightSession;
class KLightClientSession;

class KClientPort final : public KSynchronizationObject {
MESOSPHERE_AUTOOBJECT_TRAITS(KClientPort, KSynchronizationObject);
Expand All @@ -33,6 +37,8 @@ namespace ams::kern {
virtual ~KClientPort() { /* ... */ }

void Initialize(KPort *parent, s32 max_sessions);
void OnSessionFinalized();
void OnServerClosed();

constexpr const KPort *GetParent() const { return this->parent; }

Expand All @@ -43,6 +49,7 @@ namespace ams::kern {
virtual bool IsSignaled() const override;

/* TODO: More of KClientPort. */
Result CreateSession(KClientSession **out);
};

}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ namespace ams::kern {
constexpr const KSession *GetParent() const { return this->parent; }

/* TODO: More of KClientSession. */
void OnServerClosed();
};

}
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ namespace ams::kern {

return Delete(obj.GetPointerUnsafe(), name);
}

template<typename Derived> requires std::derived_from<Derived, KAutoObject>
static KScopedAutoObject<Derived> Find(const char *name) {
return Find(name);
}
private:
static KScopedAutoObject<KAutoObject> FindImpl(const char *name);

Expand Down
6 changes: 5 additions & 1 deletion libraries/libmesosphere/include/mesosphere/kern_k_port.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@

namespace ams::kern {

class KServerSession;
class KLightServerSession;

class KPort final : public KAutoObjectWithSlabHeapAndContainer<KPort, KAutoObjectWithList> {
MESOSPHERE_AUTOOBJECT_TRAITS(KPort, KAutoObject);
private:
Expand Down Expand Up @@ -50,7 +53,8 @@ namespace ams::kern {
uintptr_t GetName() const { return this->name; }
bool IsLight() const { return this->is_light; }

/* TODO: More of KPort */
Result EnqueueSession(KServerSession *session);
Result EnqueueSession(KLightServerSession *session);

KClientPort &GetClientPort() { return this->client; }
KServerPort &GetServerPort() { return this->server; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ namespace ams::kern {
virtual ~KServerPort() { /* ... */ }

void Initialize(KPort *parent);
void EnqueueSession(KServerSession *session);
void EnqueueSession(KLightServerSession *session);

constexpr const KPort *GetParent() const { return this->parent; }

Expand All @@ -47,7 +49,7 @@ namespace ams::kern {
virtual void Destroy() override;
virtual bool IsSignaled() const override;

/* TODO: More of KClientPort. */
/* TODO: More of KServerPort. */
private:
void CleanupSessions();
/* TODO: This is a placeholder definition. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,16 @@ namespace ams::kern {
constexpr KServerSession() : parent(), request_list(), current_request(), lock() { /* ... */ }
virtual ~KServerSession() { /* ... */ }

void Initialize(KSession *parent);
void Initialize(KSession *p) { this->parent = p; }

constexpr const KSession *GetParent() const { return this->parent; }

virtual bool IsSignaled() const override { MESOSPHERE_UNIMPLEMENTED(); }

/* TODO: More of KServerSession. */
Result OnRequest(KSessionRequest *request);

void OnClientClosed();
};

}
11 changes: 10 additions & 1 deletion libraries/libmesosphere/include/mesosphere/kern_k_session.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,21 @@ namespace ams::kern {

virtual ~KSession() { /* ... */ }

void Initialize(KClientPort *client_port, uintptr_t name);
virtual void Finalize() override;

virtual bool IsInitialized() const override { return this->initialized; }
virtual uintptr_t GetPostDestroyArgument() const override { return reinterpret_cast<uintptr_t>(this->process); }

static void PostDestroy(uintptr_t arg);

/* TODO: This is a placeholder definition. */
void OnServerClosed();
void OnClientClosed();

bool IsServerClosed() const { return this->state != State::Normal; }
bool IsClientClosed() const { return this->state != State::Normal; }

Result OnRequest(KSessionRequest *request) { return this->server.OnRequest(request); }

KClientSession &GetClientSession() { return this->client; }
KServerSession &GetServerSession() { return this->server; }
Expand Down
80 changes: 80 additions & 0 deletions libraries/libmesosphere/source/kern_k_client_port.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,19 @@ namespace ams::kern {
this->max_sessions = max_sessions;
}

void KClientPort::OnSessionFinalized() {
KScopedSchedulerLock sl;

const auto prev = this->num_sessions--;
if (prev == this->max_sessions) {
this->NotifyAvailable();
}
}

void KClientPort::OnServerClosed() {
MESOSPHERE_ASSERT_THIS();
}

bool KClientPort::IsLight() const {
return this->GetParent()->IsLight();
}
Expand All @@ -43,4 +56,71 @@ namespace ams::kern {
return this->num_sessions < this->max_sessions;
}

Result KClientPort::CreateSession(KClientSession **out) {
MESOSPHERE_ASSERT_THIS();

/* Reserve a new session from the resource limit. */
KScopedResourceReservation session_reservation(GetCurrentProcessPointer(), ams::svc::LimitableResource_SessionCountMax);
R_UNLESS(session_reservation.Succeeded(), svc::ResultLimitReached());

/* Update the session counts. */
{
/* Atomically increment the number of sessions. */
s32 new_sessions;
{
const auto max = this->max_sessions;
auto cur_sessions = this->num_sessions.load(std::memory_order_acquire);
do {
R_UNLESS(cur_sessions < max, svc::ResultOutOfSessions());
new_sessions = cur_sessions + 1;
} while (!this->num_sessions.compare_exchange_weak(cur_sessions, new_sessions, std::memory_order_relaxed));

}

/* Atomically update the peak session tracking. */
{
auto peak = this->peak_sessions.load(std::memory_order_acquire);
do {
if (peak >= new_sessions) {
break;
}
} while (!this->peak_sessions.compare_exchange_weak(peak, new_sessions, std::memory_order_relaxed));
}
}

/* Create a new session. */
KSession *session = KSession::Create();
if (session == nullptr) {
/* Decrement the session count. */
const auto prev = this->num_sessions--;
if (prev == this->max_sessions) {
this->NotifyAvailable();
}

return svc::ResultOutOfResource();
}

/* Initialize the session. */
session->Initialize(this, this->parent->GetName());

/* Commit the session reservation. */
session_reservation.Commit();

/* Register the session. */
KSession::Register(session);
auto session_guard = SCOPE_GUARD {
session->GetClientSession().Close();
session->GetServerSession().Close();
};

/* Enqueue the session with our parent. */
R_TRY(this->parent->EnqueueSession(std::addressof(session->GetServerSession())));

/* We succeeded, so set the output. */
session_guard.Cancel();
*out = std::addressof(session->GetClientSession());
return ResultSuccess();

}

}
24 changes: 24 additions & 0 deletions libraries/libmesosphere/source/kern_k_client_session.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <mesosphere.hpp>

namespace ams::kern {

void KClientSession::OnServerClosed() {
MESOSPHERE_ASSERT_THIS();
}

}
34 changes: 32 additions & 2 deletions libraries/libmesosphere/source/kern_k_port.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,41 @@ namespace ams::kern {
}

void KPort::OnClientClosed() {
MESOSPHERE_UNIMPLEMENTED();
MESOSPHERE_ASSERT_THIS();

KScopedSchedulerLock sl;

if (this->state == State::Normal) {
this->state = State::ClientClosed;
}
}

void KPort::OnServerClosed() {
MESOSPHERE_UNIMPLEMENTED();
MESOSPHERE_ASSERT_THIS();

KScopedSchedulerLock sl;

if (this->state == State::Normal) {
this->state = State::ServerClosed;
}
}

Result KPort::EnqueueSession(KServerSession *session) {
KScopedSchedulerLock sl;

R_UNLESS(this->state == State::Normal, svc::ResultPortClosed());

this->server.EnqueueSession(session);
return ResultSuccess();
}

Result KPort::EnqueueSession(KLightServerSession *session) {
KScopedSchedulerLock sl;

R_UNLESS(this->state == State::Normal, svc::ResultPortClosed());

this->server.EnqueueSession(session);
return ResultSuccess();
}

}
28 changes: 27 additions & 1 deletion libraries/libmesosphere/source/kern_k_server_port.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,33 @@ namespace ams::kern {
if (this->IsLight()) {
return !this->light_session_list.empty();
} else {
return this->session_list.empty();
return !this->session_list.empty();
}
}

void KServerPort::EnqueueSession(KServerSession *session) {
MESOSPHERE_ASSERT_THIS();
MESOSPHERE_ASSERT(!this->IsLight());

KScopedSchedulerLock sl;

/* Add the session to our queue. */
this->session_list.push_back(*session);
if (this->session_list.size() == 1) {
this->NotifyAvailable();
}
}

void KServerPort::EnqueueSession(KLightServerSession *session) {
MESOSPHERE_ASSERT_THIS();
MESOSPHERE_ASSERT(this->IsLight());

KScopedSchedulerLock sl;

/* Add the session to our queue. */
this->light_session_list.push_back(*session);
if (this->light_session_list.size() == 1) {
this->NotifyAvailable();
}
}

Expand Down
Loading

0 comments on commit 7400a8f

Please sign in to comment.