hrev45811 adds 2 changesets to branch 'master' old head: a97ff1bb60f6c3adddc121296175de58cb3f632c new head: 2eb2b522bf0b3533a7a35bc5fa8d1caa0d2573d2 overview: http://cgit.haiku-os.org/haiku/log/?qt=range&q=2eb2b52+%5Ea97ff1b ---------------------------------------------------------------------------- cbcde3b: kernel team.cpp: fix unbalanced io_context ref management ... in case of team creation error. Once assigned to Team::io_context the Team object takes responsibility of the I/O context object and releases the reference on destruction. load_image_internal() and fork_team() were thus releasing one reference too many. Fixes #9851. 2eb2b52: Enforce team and thread limits Also fixes incorrect team accounting in case of error when creating a team. The previously incremented sUsedTeams wasn't decremented again. [ Ingo Weinhold <ingo_weinhold@xxxxxx> ] ---------------------------------------------------------------------------- 2 files changed, 46 insertions(+), 12 deletions(-) src/system/kernel/team.cpp | 33 ++++++++++++++++++++++++--------- src/system/kernel/thread.cpp | 25 ++++++++++++++++++++++--- ############################################################################ Commit: cbcde3ba8058d84d86d3a36b1ebbec37ed1f35ea URL: http://cgit.haiku-os.org/haiku/commit/?id=cbcde3b Author: Ingo Weinhold <ingo_weinhold@xxxxxx> Date: Mon Jul 1 23:16:02 2013 UTC Ticket: https://dev.haiku-os.org/ticket/9851 kernel team.cpp: fix unbalanced io_context ref management ... in case of team creation error. Once assigned to Team::io_context the Team object takes responsibility of the I/O context object and releases the reference on destruction. load_image_internal() and fork_team() were thus releasing one reference too many. Fixes #9851. ---------------------------------------------------------------------------- diff --git a/src/system/kernel/team.cpp b/src/system/kernel/team.cpp index 1212b62..abd52ed 100644 --- a/src/system/kernel/team.cpp +++ b/src/system/kernel/team.cpp @@ -503,7 +503,8 @@ Team::~Team() // get rid of all associated data PrepareForDeletion(); - vfs_put_io_context(io_context); + if (io_context != NULL) + vfs_put_io_context(io_context); delete_owned_ports(this); sem_delete_owned_sems(this); @@ -1752,7 +1753,7 @@ load_image_internal(char**& _flatArgs, size_t flatArgsSize, int32 argCount, status = VMAddressSpace::Create(team->id, USER_BASE, USER_SIZE, false, &team->address_space); if (status != B_OK) - goto err3; + goto err2; // create the user data area status = create_team_user_data(team); @@ -1814,8 +1815,6 @@ err5: delete_team_user_data(team); err4: team->address_space->Put(); -err3: - vfs_put_io_context(team->io_context); err2: free_team_arg(teamArgs); err1: @@ -2075,7 +2074,7 @@ fork_team(void) parentTeam->realtime_sem_context); if (team->realtime_sem_context == NULL) { status = B_NO_MEMORY; - goto err25; + goto err2; } } @@ -2170,8 +2169,6 @@ err4: team->address_space->RemoveAndPut(); err3: delete_realtime_sem_context(team->realtime_sem_context); -err25: - vfs_put_io_context(team->io_context); err2: free(forkArgs); err1: ############################################################################ Revision: hrev45811 Commit: 2eb2b522bf0b3533a7a35bc5fa8d1caa0d2573d2 URL: http://cgit.haiku-os.org/haiku/commit/?id=2eb2b52 Author: Ingo Weinhold <ingo_weinhold@xxxxxx> Date: Mon Jul 1 23:55:04 2013 UTC Enforce team and thread limits Also fixes incorrect team accounting in case of error when creating a team. The previously incremented sUsedTeams wasn't decremented again. ---------------------------------------------------------------------------- diff --git a/src/system/kernel/team.cpp b/src/system/kernel/team.cpp index abd52ed..c5b0f7e 100644 --- a/src/system/kernel/team.cpp +++ b/src/system/kernel/team.cpp @@ -1707,7 +1707,9 @@ load_image_internal(char**& _flatArgs, size_t flatArgsSize, int32 argCount, InterruptsSpinLocker teamsLocker(sTeamHashLock); sTeamHash.Insert(team); - sUsedTeams++; + bool teamLimitReached = sUsedTeams >= sMaxTeams; + if (!teamLimitReached) + sUsedTeams++; teamsLocker.Unlock(); @@ -1727,6 +1729,11 @@ load_image_internal(char**& _flatArgs, size_t flatArgsSize, int32 argCount, // check the executable's set-user/group-id permission update_set_id_user_and_group(team, path); + if (teamLimitReached) { + status = B_NO_MORE_TEAMS; + goto err1; + } + status = create_team_arg(&teamArgs, path, flatArgs, flatArgsSize, argCount, envCount, (mode_t)-1, errorPort, errorToken); if (status != B_OK) @@ -1834,6 +1841,8 @@ err1: teamsLocker.Lock(); sTeamHash.Remove(team); + if (!teamLimitReached) + sUsedTeams--; teamsLocker.Unlock(); sNotificationService.Notify(TEAM_REMOVED, team); @@ -2038,7 +2047,9 @@ fork_team(void) InterruptsSpinLocker teamsLocker(sTeamHashLock); sTeamHash.Insert(team); - sUsedTeams++; + bool teamLimitReached = sUsedTeams >= sMaxTeams; + if (!teamLimitReached) + sUsedTeams++; teamsLocker.Unlock(); @@ -2055,6 +2066,11 @@ fork_team(void) team->debug_info.flags |= atomic_get(&parentTeam->debug_info.flags) & B_TEAM_DEBUG_INHERITED_FLAGS; + if (teamLimitReached) { + status = B_NO_MORE_TEAMS; + goto err1; + } + forkArgs = (arch_fork_arg*)malloc(sizeof(arch_fork_arg)); if (forkArgs == NULL) { status = B_NO_MEMORY; @@ -2185,6 +2201,8 @@ err1: teamsLocker.Lock(); sTeamHash.Remove(team); + if (!teamLimitReached) + sUsedTeams--; teamsLocker.Unlock(); sNotificationService.Notify(TEAM_REMOVED, team); diff --git a/src/system/kernel/thread.cpp b/src/system/kernel/thread.cpp index 7ac994c..7e29df2 100644 --- a/src/system/kernel/thread.cpp +++ b/src/system/kernel/thread.cpp @@ -1015,19 +1015,38 @@ thread_create_thread(const ThreadCreationAttributes& attributes, bool kernel) } // We're going to make the thread live, now. The thread itself will take - // over a reference to its Thread object. We acquire another reference for - // our own use (and threadReference remains armed). - thread->AcquireReference(); + // over a reference to its Thread object. We'll acquire another reference + // for our own use (and threadReference remains armed). ThreadLocker threadLocker(thread); InterruptsSpinLocker schedulerLocker(gSchedulerLock); SpinLocker threadHashLocker(sThreadHashLock); + // check the thread limit + if (sUsedThreads >= sMaxThreads) { + // Clean up the user_thread structure. It's a bit unfortunate that the + // Thread destructor cannot do that, so we have to do that explicitly. + threadHashLocker.Unlock(); + schedulerLocker.Unlock(); + + user_thread* userThread = thread->user_thread; + thread->user_thread = NULL; + + threadLocker.Unlock(); + + if (userThread != NULL) + team_free_user_thread(team, userThread); + + return B_NO_MORE_THREADS; + } + // make thread visible in global hash/list thread->visible = true; sUsedThreads++; scheduler_on_thread_init(thread); + thread->AcquireReference(); + // Debug the new thread, if the parent thread required that (see above), // or the respective global team debug flag is set. But only, if a // debugger is installed for the team.