Skip to content

Commit 02cebd5

Browse files
authored
Optimize handles clearing on session / token closing (#851)
1 parent 34c2a83 commit 02cebd5

2 files changed

Lines changed: 74 additions & 38 deletions

File tree

src/lib/handle_mgr/HandleManager.cpp

Lines changed: 65 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ CK_SESSION_HANDLE HandleManager::addSession(CK_SLOT_ID slotID, CK_VOID_PTR sessi
6767
Handle h( CKH_SESSION, slotID );
6868
h.object = session;
6969
handles[++handleCounter] = h;
70+
slotHandles[slotID].insert(handleCounter);
71+
slotSessionCount[slotID]++;
7072
return (CK_SESSION_HANDLE)handleCounter;
7173
}
7274

@@ -100,6 +102,8 @@ CK_OBJECT_HANDLE HandleManager::addSessionObject(CK_SLOT_ID slotID, CK_SESSION_H
100102
h.object = object;
101103
handles[++handleCounter] = h;
102104
objects[object] = handleCounter;
105+
sessionObjectHandles[hSession].insert(handleCounter);
106+
slotHandles[slotID].insert(handleCounter);
103107
return (CK_OBJECT_HANDLE)handleCounter;
104108
}
105109

@@ -124,6 +128,7 @@ CK_OBJECT_HANDLE HandleManager::addTokenObject(CK_SLOT_ID slotID, bool isPrivate
124128
h.object = object;
125129
handles[++handleCounter] = h;
126130
objects[object] = handleCounter;
131+
slotHandles[slotID].insert(handleCounter);
127132
return (CK_OBJECT_HANDLE)handleCounter;
128133
}
129134

@@ -153,83 +158,105 @@ void HandleManager::destroyObject(const CK_OBJECT_HANDLE hObject)
153158

154159
std::map< CK_ULONG, Handle>::iterator it = handles.find(hObject);
155160
if (it != handles.end() && CKH_OBJECT == it->second.kind) {
161+
// Remove from secondary indexes
162+
if (it->second.hSession != CK_INVALID_HANDLE)
163+
sessionObjectHandles[it->second.hSession].erase(hObject);
164+
slotHandles[it->second.slotID].erase(hObject);
165+
156166
objects.erase(it->second.object);
157167
handles.erase(it);
158168
}
159169
}
160170

161171
void HandleManager::sessionClosed(const CK_SESSION_HANDLE hSession)
162172
{
163-
CK_SLOT_ID slotID;
164173
MutexLocker lock(handlesMutex);
165174

166175
std::map< CK_ULONG, Handle>::iterator it = handles.find(hSession);
167176
if (it == handles.end() || CKH_SESSION != it->second.kind)
168177
return; // Unable to find the specified session.
169178

170-
slotID = it->second.slotID;
179+
CK_SLOT_ID slotID = it->second.slotID;
171180

172181
// session closed, so we can erase information about it.
182+
slotHandles[slotID].erase(hSession);
173183
handles.erase(it);
174184

175-
// Erase all session object handles associated with the given session handle.
176-
CK_ULONG openSessionCount = 0;
177-
for (it = handles.begin(); it != handles.end(); ) {
178-
Handle &h = it->second;
179-
if (CKH_SESSION == h.kind && slotID == h.slotID) {
180-
++openSessionCount; // another session is open for this slotID.
181-
} else {
182-
if (CKH_OBJECT == h.kind && hSession == h.hSession) {
183-
// A session object is present for the given session, so erase it.
184-
objects.erase(it->second.object);
185-
// Iterator post-incrementing (it++) will return a copy of the original it (which points to handle to be deleted).
186-
handles.erase(it++);
187-
continue;
185+
// Erase all session object handles associated with the given session handle
186+
// using the secondary index instead of scanning the entire handles map.
187+
std::map< CK_SESSION_HANDLE, std::set<CK_ULONG> >::iterator soit = sessionObjectHandles.find(hSession);
188+
if (soit != sessionObjectHandles.end()) {
189+
std::set<CK_ULONG>& objHandles = soit->second;
190+
for (std::set<CK_ULONG>::iterator oit = objHandles.begin(); oit != objHandles.end(); ++oit) {
191+
std::map< CK_ULONG, Handle>::iterator hit = handles.find(*oit);
192+
if (hit != handles.end()) {
193+
objects.erase(hit->second.object);
194+
slotHandles[slotID].erase(*oit);
195+
handles.erase(hit);
188196
}
189197
}
190-
++it;
198+
sessionObjectHandles.erase(soit);
191199
}
192200

193-
// We are done when there are still sessions open.
194-
if (openSessionCount)
201+
// Use the session counter to check if there are remaining open sessions.
202+
CK_ULONG& count = slotSessionCount[slotID];
203+
if (count > 0)
204+
count--;
205+
206+
if (count > 0)
195207
return;
196208

197-
// No more sessions open for this token, so remove all object handles that are still valid for the given slotID.
209+
// No more sessions open for this token, so remove all remaining object handles (token objects)
210+
// for the given slotID.
211+
slotSessionCount.erase(slotID);
198212
allSessionsClosed(slotID, true);
199213
}
200214

201215
void HandleManager::allSessionsClosed(const CK_SLOT_ID slotID, bool isLocked)
202216
{
203217
MutexLocker lock(isLocked ? NULL : handlesMutex);
204218

205-
// Erase all "session", "session object" and "token object" handles for a given slot id.
206-
std::map< CK_ULONG, Handle>::iterator it;
207-
for (it = handles.begin(); it != handles.end(); ) {
208-
Handle &h = it->second;
209-
if (slotID == h.slotID) {
210-
if (CKH_OBJECT == it->second.kind)
211-
objects.erase(it->second.object);
212-
// Iterator post-incrementing (it++) will return a copy of the original it (which points to handle to be deleted).
213-
handles.erase(it++);
214-
continue;
219+
// Erase all "session", "session object" and "token object" handles for a given slot id
220+
// using the per-slot index instead of scanning the entire handles map.
221+
std::map< CK_SLOT_ID, std::set<CK_ULONG> >::iterator sit = slotHandles.find(slotID);
222+
if (sit != slotHandles.end()) {
223+
std::set<CK_ULONG>& handleSet = sit->second;
224+
for (std::set<CK_ULONG>::iterator it = handleSet.begin(); it != handleSet.end(); ++it) {
225+
std::map< CK_ULONG, Handle>::iterator hit = handles.find(*it);
226+
if (hit != handles.end()) {
227+
if (CKH_OBJECT == hit->second.kind)
228+
objects.erase(hit->second.object);
229+
if (CKH_SESSION == hit->second.kind)
230+
sessionObjectHandles.erase(*it);
231+
handles.erase(hit);
232+
}
215233
}
216-
++it;
234+
slotHandles.erase(sit);
217235
}
236+
237+
slotSessionCount.erase(slotID);
218238
}
219239

220240
void HandleManager::tokenLoggedOut(const CK_SLOT_ID slotID)
221241
{
222242
MutexLocker lock(handlesMutex);
223243

224-
// Erase all private "token object" or "session object" handles for a given slot id.
225-
std::map< CK_ULONG, Handle>::iterator it;
226-
for (it = handles.begin(); it != handles.end(); ) {
227-
Handle &h = it->second;
228-
if (CKH_OBJECT == h.kind && slotID == h.slotID && h.isPrivate) {
244+
// Erase all private "token object" or "session object" handles for a given slot id
245+
// using the per-slot index instead of scanning the entire handles map.
246+
std::map< CK_SLOT_ID, std::set<CK_ULONG> >::iterator sit = slotHandles.find(slotID);
247+
if (sit == slotHandles.end())
248+
return;
249+
250+
std::set<CK_ULONG>& handleSet = sit->second;
251+
for (std::set<CK_ULONG>::iterator it = handleSet.begin(); it != handleSet.end(); ) {
252+
std::map< CK_ULONG, Handle>::iterator hit = handles.find(*it);
253+
if (hit != handles.end() && CKH_OBJECT == hit->second.kind && hit->second.isPrivate) {
229254
// A private object is present for the given slotID so we need to remove it.
230-
objects.erase(it->second.object);
231-
// Iterator post-incrementing (it++) will return a copy of the original it (which points to handle to be deleted).
232-
handles.erase(it++);
255+
objects.erase(hit->second.object);
256+
if (hit->second.hSession != CK_INVALID_HANDLE)
257+
sessionObjectHandles[hit->second.hSession].erase(*it);
258+
handles.erase(hit);
259+
handleSet.erase(it++);
233260
continue;
234261
}
235262
++it;

src/lib/handle_mgr/HandleManager.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include "cryptoki.h"
3939

4040
#include <map>
41+
#include <set>
4142

4243
#define CK_INTERNAL_SESSION_HANDLE CK_SESSION_HANDLE
4344

@@ -88,6 +89,14 @@ class HandleManager
8889
std::map< CK_ULONG, Handle> handles;
8990
std::map< CK_VOID_PTR, CK_ULONG> objects;
9091
CK_ULONG handleCounter;
92+
93+
// Secondary indexes for efficient cleanup without full-map scans.
94+
// Maps a session handle to the set of object handles created in that session.
95+
std::map< CK_SESSION_HANDLE, std::set<CK_ULONG> > sessionObjectHandles;
96+
// Maps a slot ID to the set of all handles (sessions + objects) for that slot.
97+
std::map< CK_SLOT_ID, std::set<CK_ULONG> > slotHandles;
98+
// Tracks the number of open sessions per slot to avoid counting scans.
99+
std::map< CK_SLOT_ID, CK_ULONG> slotSessionCount;
91100
};
92101

93102
#endif // !_SOFTHSM_V2_HANDLEMANAGER_H

0 commit comments

Comments
 (0)