From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/winstation.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-)
diff --git a/dlls/win32u/winstation.c b/dlls/win32u/winstation.c index e5fe36ff566..deb4cd0bf02 100644 --- a/dlls/win32u/winstation.c +++ b/dlls/win32u/winstation.c @@ -49,27 +49,45 @@ static struct shared_session *shared_session; struct shared_session { LONG ref; + LONG weak_ref; UINT64 id; SIZE_T size; UINT object_capacity; const session_shm_t *shared; };
+/* try acquiring a strong reference from a possibly weak referenced session */ static struct shared_session *shared_session_acquire( struct shared_session *session ) { - int ref = InterlockedIncrement( &session->ref ); - TRACE( "session %p incrementing ref to %d\n", session, ref ); - return session; + if (InterlockedOr( &session->ref, 0 )) + { + int ref = InterlockedIncrement( &session->ref ); + TRACE( "session %p incrementing ref to %d\n", session, ref ); + return session; + } + + TRACE( "session %p failed to upgrade from weak ref\n", session ); + return NULL; +} + +/* release a weak reference on a session */ +static void shared_session_release_weak( struct shared_session *session ) +{ + int ref = InterlockedDecrement( &session->weak_ref ); + TRACE( "session %p decrementing weak_ref to %d\n", session, ref ); + if (!ref) free( session ); }
+/* release a strong reference on a session */ static void shared_session_release( struct shared_session *session ) { int ref = InterlockedDecrement( &session->ref ); TRACE( "session %p decrementing ref to %d\n", session, ref ); if (!ref) { + /* global shared_session has a strong reference, unmap when strong refcount reaches 0. */ NtUnmapViewOfSection( GetCurrentProcess(), (void *)session->shared ); - free( session ); + shared_session_release_weak( session ); } }
@@ -99,6 +117,7 @@ static NTSTATUS map_shared_session_section( struct shared_session *session, HAND return status; }
+/* return a strong reference on the last known valid session */ static struct shared_session *get_shared_session( BOOL force ) { struct shared_session *session; @@ -123,6 +142,7 @@ static struct shared_session *get_shared_session( BOOL force ) return NULL; } session->ref = 1; + session->weak_ref = 1;
InitializeObjectAttributes( &attr, &name, 0, NULL, NULL ); if (!(status = NtOpenSection( &handle, SECTION_MAP_READ | SECTION_QUERY, &attr )))