Index: uspace/lib/cpp/include/internal/memory/shared_payload.hpp
===================================================================
--- uspace/lib/cpp/include/internal/memory/shared_payload.hpp	(revision e13c378e9d5264d41d4fb768c87e72f027e44c2b)
+++ uspace/lib/cpp/include/internal/memory/shared_payload.hpp	(revision 5735b111658877f228a008dd9c4a97ca2d4c7a7b)
@@ -30,5 +30,14 @@
 #define LIBCPP_INTERNAL_MEMORY_SHARED_PAYLOAD
 
-#include <internal/list.hpp>
+#include <cinttypes>
+#include <utility>
+
+namespace std
+{
+    template<class>
+    struct default_delete;
+
+    struct allocator_arg_t;
+}
 
 namespace std::aux
@@ -40,54 +49,136 @@
     using refcount_t = long;
 
+    template<class D, class T>
+    void use_payload_deleter(D* deleter, T* data)
+    {
+        if (deleter)
+            (*deleter)(data);
+    }
+
     template<class T>
-    class shared_payload
+    class shared_payload_base
     {
         public:
+            virtual void destroy() = 0;
+            virtual T* get() const noexcept = 0;
+
+            virtual uint8_t* deleter() const noexcept = 0;
+
+            virtual void increment() noexcept = 0;
+            virtual void increment_weak() noexcept = 0;
+            virtual bool decrement() noexcept = 0;
+            virtual bool decrement_weak() noexcept = 0;
+            virtual refcount_t refs() const noexcept = 0;
+            virtual refcount_t weak_refs() const noexcept = 0;
+            virtual bool expired() const noexcept = 0;
+
+            virtual ~shared_payload_base() = default;
+    };
+
+    template<class T, class D = default_delete<T>>
+    class shared_payload: public shared_payload_base<T>
+    {
+        public:
+            shared_payload(T* ptr, D deleter = D{})
+                : data_{ptr}, deleter_{deleter},
+                  refcount_{1}, weak_refcount_{1}
+            { /* DUMMY BODY */ }
 
             template<class... Args>
             shared_payload(Args&&... args)
+                : data_{new T{forward<Args>(args)...}},
+                  deleter_{}, refcount_{1}, weak_refcount_{1}
             { /* DUMMY BODY */ }
 
             template<class Alloc, class... Args>
-            shared_payloda(Alloc alloc, Args&&... args)
-            { /* DUMMY BODY */ }
+            shared_payload(allocator_arg_t, Alloc alloc, Args&&... args)
+                : data_{alloc.allocate(1)},
+                  deleter_{}, refcount_{1}, weak_refcount_{1}
+            {
+                alloc.construct(data_, forward<Args>(args)...);
+            }
 
-            T* get() const
+            template<class Alloc, class... Args>
+            shared_payload(D deleter, Alloc alloc, Args&&... args)
+                : data_{alloc.allocate(1)},
+                  deleter_{deleter}, refcount_{1}, weak_refcount_{1}
+            {
+                alloc.construct(data_, forward<Args>(args)...);
+            }
+
+            void destroy() override
+            {
+                if (refs() == 0)
+                {
+                    if (data_)
+                    {
+                        deleter_(data_);
+                        data_ = nullptr;
+                    }
+
+                    if (weak_refs() == 0)
+                        delete this;
+                }
+            }
+
+            T* get() const noexcept override
             {
                 return data_;
             }
 
-            void increment_refcount()
+            uint8_t* deleter() const noexcept override
             {
-                ++refcount_;
+                return (uint8_t*)&deleter_;
             }
 
-            void increment_weak_refcount()
+            void increment() noexcept override
             {
-                ++weak_refcount_;
+                __atomic_add_fetch(&refcount_, 1, __ATOMIC_ACQ_REL);
             }
 
-            bool decrement_refcount()
+            void increment_weak() noexcept override
             {
-                return --refcount_ == 0;
+                __atomic_add_fetch(&weak_refcount_, 1, __ATOMIC_ACQ_REL);
             }
 
-            bool decrement_weak_refcount()
+            bool decrement() noexcept override
             {
-                return --weak_refcount_ == 0;
+                if (__atomic_sub_fetch(&refcount_, 1, __ATOMIC_ACQ_REL) == 0)
+                    return decrement_weak();
+                else
+                    return false;
             }
 
-            refcount_t refs() const
+            bool decrement_weak() noexcept override
             {
-                return refcount_;
+                return __atomic_sub_fetch(&weak_refcount_, 1, __ATOMIC_ACQ_REL) == 0 && refs() == 0;
             }
 
-            refcount_t weak_refs() const
+            refcount_t refs() const noexcept override
             {
-                return weak_refcount_;
+                return __atomic_load_n(&refcount_, __ATOMIC_RELAXED);
+            }
+
+            refcount_t weak_refs() const noexcept override
+            {
+                return __atomic_load_n(&weak_refcount_, __ATOMIC_RELAXED);
+            }
+
+            bool expired() const noexcept override
+            {
+                return refs() == 0;
             }
 
         private:
             T* data_;
+            D deleter_;
+
+            /**
+             * We're using a trick where refcount_ > 0
+             * means weak_refcount_ has 1 added to it,
+             * this makes it easier for weak_ptrs that
+             * can't decrement the weak_refcount_ to
+             * zero with shared_ptrs using this object.
+             */
             refcount_t refcount_;
             refcount_t weak_refcount_;
Index: uspace/lib/cpp/include/internal/memory/shared_ptr.hpp
===================================================================
--- uspace/lib/cpp/include/internal/memory/shared_ptr.hpp	(revision e13c378e9d5264d41d4fb768c87e72f027e44c2b)
+++ uspace/lib/cpp/include/internal/memory/shared_ptr.hpp	(revision 5735b111658877f228a008dd9c4a97ca2d4c7a7b)
@@ -32,8 +32,13 @@
 #include <exception>
 #include <functional>
+#include <internal/memory/allocator_arg.hpp>
+#include <internal/memory/shared_payload.hpp>
 #include <type_traits>
 
 namespace std
 {
+    template<class T>
+    class weak_ptr;
+
     /**
      * 20.8.2.1, class bad_weak_ptr:
@@ -65,39 +70,140 @@
              */
 
-            constexpr shared_ptr() noexcept;
-
-            template<class U>
-            explicit shared_ptr(U* ptr);
+            constexpr shared_ptr() noexcept
+                : payload_{}, data_{}
+            { /* DUMMY BODY */ }
+
+            template<class U>
+            explicit shared_ptr(
+                enable_if_t<is_convertible_v<U*, element_type*>, U*> ptr
+            )
+                : payload_{}, data_{ptr}
+            {
+                try
+                {
+                    payload_ = new aux::shared_payload<T>{ptr};
+                }
+                catch (const bad_alloc&)
+                {
+                    delete ptr;
+
+                    throw;
+                }
+            }
 
             template<class U, class D>
-            shared_ptr(U* ptr, D deleter);
+            shared_ptr(
+                enable_if_t<is_convertible_v<U*, element_type*>, U*> ptr, D deleter
+            )
+                : shared_ptr{}
+            {
+                try
+                {
+                    payload_ = new aux::shared_payload<T, D>{ptr, deleter};
+                }
+                catch (const bad_alloc&)
+                {
+                    deleter(ptr);
+
+                    throw;
+                }
+            }
 
             template<class U, class D, class A>
-            shared_ptr(U* ptr, D deleter, A alloc);
+            shared_ptr(
+                enable_if_t<is_convertible_v<U*, element_type*>, U*> ptr,
+                D deleter, A
+            )
+                : shared_ptr{}
+            {
+                try
+                {
+                    payload_ = new aux::shared_payload<T, D>{ptr, deleter};
+                }
+                catch (const bad_alloc&)
+                {
+                    deleter(ptr);
+
+                    throw;
+                }
+            }
 
             template<class D>
-            shared_ptr(nullptr_t, D deleter);
+            shared_ptr(nullptr_t ptr, D deleter)
+                : shared_ptr{}
+            { /* DUMMY BODY */ }
 
             template<class D, class A>
-            shared_ptr(nullptr_t, D deleter, A alloc);
-
-            template<class U>
-            shared_ptr(const shared_ptr<U>& other, value_type* ptr);
-
-            shared_ptr(const shared_ptr& other);
-
-            template<class U>
-            shared_ptr(const shared_ptr<U>& other);
-
-            shared_ptr(shared_ptr&& other);
-
-            template<class U>
-            shared_ptr(shared_ptr<U>&& other);
-
-            template<class U>
-            explicit shared_ptr(const weak_ptr<U>& other);
+            shared_ptr(nullptr_t, D deleter, A)
+                : shared_ptr{}
+            { /* DUMMY BODY */ }
+
+            template<class U>
+            shared_ptr(
+                enable_if_t<is_convertible_v<U*, element_type*>, const shared_ptr<U>&> other,
+                element_type* ptr
+            )
+                : payload_{other.payload_}, data_{ptr}
+            {
+                if (payload_)
+                    payload_->increment();
+            }
+
+            shared_ptr(const shared_ptr& other)
+                : payload_{other.payload_}, data_{other.data_}
+            {
+                if (payload_)
+                    payload_->increment();
+            }
+
+            template<class U>
+            shared_ptr(
+                enable_if_t<is_convertible_v<U*, element_type*>, const shared_ptr<U>&> other
+            )
+                : payload_{other.payload_}, data_{other.data_}
+            {
+                if (payload_)
+                    payload_->increment();
+            }
+
+            shared_ptr(shared_ptr&& other)
+                : payload_{move(other.payload_)}, data_{move(other.data_)}
+            {
+                other.payload_ = nullptr;
+                other.data_ = nullptr;
+            }
+
+            template<class U>
+            shared_ptr(
+                enable_if_t<is_convertible_v<U*, element_type*>, shared_ptr<U>&&> other
+            )
+                : payload_{move(other.payload_)}, data_{move(other.data_)}
+            {
+                other.payload_ = nullptr;
+                other.data_ = nullptr;
+            }
+
+            template<class U>
+            explicit shared_ptr(
+                enable_if_t<is_convertible_v<U*, element_type*>, const weak_ptr<U>&> other
+            )
+            {
+                if (other.expired())
+                    throw bad_weak_ptr{};
+                // TODO:
+            }
 
             template<class U, class D>
-            shared_ptr(unique_ptr<U, D>&& other);
+            shared_ptr(
+                enable_if_t<
+                    is_convertible_v<
+                        typename unique_ptr<U, D>::pointer,
+                        element_type*
+                    >,
+                    unique_ptr<U, D>&&
+                > other
+            ) // TODO: if D is a reference type, it should be ref(other.get_deleter())
+                : shared_ptr{other.release(), other.get_deleter()}
+            { /* DUMMY BODY */ }
 
             constexpr shared_ptr(nullptr_t) noexcept
@@ -109,5 +215,8 @@
              */
 
-            ~shared_ptr();
+            ~shared_ptr()
+            {
+                remove_payload_();
+            }
 
             /**
@@ -115,16 +224,57 @@
              */
 
-            shared_ptr& operator=(const shared_ptr& rhs) noexcept;
-
-            template<class U>
-            shared_ptr& operator=(const shared_ptr<U>& rhs) noexcept;
-
-            shared_ptr& operator=(shared_ptr&& rhs) noexcept;
-
-            template<class U>
-            shared_ptr& operator=(shared_ptr<U>&& rhs) noexcept;
+            shared_ptr& operator=(const shared_ptr& rhs) noexcept
+            {
+                if (rhs.payload_)
+                    rhs.payload_->increment();
+
+                remove_payload_();
+
+                payload_ = rhs.payload_;
+                data_ = rhs.data_;
+
+                return *this;
+            }
+
+            template<class U>
+            shared_ptr& operator=(
+                enable_if_t<is_convertible_v<U*, element_type*>, const shared_ptr<U>&> rhs
+            ) noexcept
+            {
+                if (rhs.payload_)
+                    rhs.payload_->increment();
+
+                remove_payload_();
+
+                payload_ = rhs.payload_;
+                data_ = rhs.data_;
+
+                return *this;
+            }
+
+            shared_ptr& operator=(shared_ptr&& rhs) noexcept
+            {
+                shared_ptr{move(rhs)}.swap(*this);
+
+                return *this;
+            }
+
+            template<class U>
+            shared_ptr& operator=(
+                enable_if_t<is_convertible_v<U*, element_type*>, shared_ptr<U>&&> rhs
+            ) noexcept
+            {
+                shared_ptr{move(rhs)}.swap(*this);
+
+                return *this;
+            }
 
             template<class U, class D>
-            shared_ptr& operator=(unique_ptr<U, D>&& rhs);
+            shared_ptr& operator=(unique_ptr<U, D>&& rhs)
+            {
+                shared_ptr{move(rhs)}.swap(*this);
+
+                return *this;
+            }
 
             /**
@@ -132,16 +282,32 @@
              */
 
-            void swap(shared_ptr& other) noexcept;
-
-            void reset() noexcept;
-
-            template<class U>
-            void reset(U* ptr);
+            void swap(shared_ptr& other) noexcept
+            {
+                std::swap(payload_, other.payload_);
+                std::swap(data_, other.data_);
+            }
+
+            void reset() noexcept
+            {
+                shared_ptr{}.swap(*this);
+            }
+
+            template<class U>
+            void reset(U* ptr)
+            {
+                shared_ptr{ptr}.swap(*this);
+            }
 
             template<class U, class D>
-            void reset(U* ptr, D deleter);
+            void reset(U* ptr, D deleter)
+            {
+                shared_ptr{ptr, deleter}.swap(*this);
+            }
 
             template<class U, class D, class A>
-            void reset(U* ptr, D deleter, A alloc);
+            void reset(U* ptr, D deleter, A alloc)
+            {
+                shared_ptr{ptr, deleter, alloc}.swap(*this);
+            }
 
             /**
@@ -151,11 +317,11 @@
             element_type* get() const noexcept
             {
-                if (payload_)
-                    return payload_->get();
-                else
-                    return nullptr;
-            }
-
-            T& operator*() const noexcept;
+                return data_;
+            }
+
+            enable_if_t<!is_void_v<T>, T&> operator*() const noexcept
+            {
+                return *data_;
+            }
 
             T* operator->() const noexcept
@@ -189,12 +355,31 @@
 
             template<class U>
-            bool owner_before(const weak_ptr<U>& ptr) const;
+            bool owner_before(const weak_ptr<U>& ptr) const
+            {
+                return payload_ < ptr.payload_;
+            }
 
         private:
-            aux::shared_payload<element_type>* payload_;
-
-            shared_ptr(aux::shared_payload<element_type>* payload)
-                : payload_{payload}
+            aux::shared_payload_base<element_type>* payload_;
+            element_type* data_;
+
+            shared_ptr(aux::shared_payload_base<element_type>* payload)
+                : payload_{payload}, data_{payload->get()}
             { /* DUMMY BODY */ }
+
+            void remove_payload_()
+            {
+                if (payload_)
+                {
+                    auto res = payload_->decrement();
+                    if (res)
+                        payload_->destroy();
+
+                    payload_ = nullptr;
+                }
+
+                if (data_)
+                    data_ = nullptr;
+            }
 
             template<class U, class... Args>
@@ -203,4 +388,10 @@
             template<class U, class A, class... Args>
             friend shared_ptr<U> allocate_shared(const A&, Args&&...);
+
+            template<class D, class U>
+            D* get_deleter(const shared_ptr<U>&) noexcept;
+
+            template<class U>
+            friend class weak_ptr;
     };
 
@@ -226,5 +417,5 @@
     {
         return shared_ptr<T>{
-            new aux::shared_payload<T>{A{alloc}, forward<Args>(args)...}
+            new aux::shared_payload<T>{allocator_arg, A{alloc}, forward<Args>(args)...}
         };
     }
@@ -394,5 +585,8 @@
     D* get_deleter(const shared_ptr<T>& ptr) noexcept
     {
-        // TODO: implement this through payload
+        if (ptr.payload_)
+            return static_cast<D*>(ptr.payload_->deleter());
+        else
+            return nullptr;
     }
 
