Make semctl IPC_INFO cmd return the index of highest used entry.

PiperOrigin-RevId: 346973338
This commit is contained in:
Jing Chen
2020-12-11 04:22:04 -08:00
committed by gVisor bot
parent 0eb4acad37
commit 73eccab91e
3 changed files with 83 additions and 4 deletions
+53
View File
@@ -52,6 +52,9 @@ type Registry struct {
mu sync.Mutex `state:"nosave"`
semaphores map[int32]*Set
lastIDUsed int32
// indexes maintains a mapping between a set's index in virtual array and
// its identifier.
indexes map[int32]int32
}
// Set represents a set of semaphores that can be operated atomically.
@@ -113,6 +116,7 @@ func NewRegistry(userNS *auth.UserNamespace) *Registry {
return &Registry{
userNS: userNS,
semaphores: make(map[int32]*Set),
indexes: make(map[int32]int32),
}
}
@@ -163,6 +167,9 @@ func (r *Registry) FindOrCreate(ctx context.Context, key, nsems int32, mode linu
}
// Apply system limits.
//
// Map semaphores and map indexes in a registry are of the same size,
// check map semaphores only here for the system limit.
if len(r.semaphores) >= setsMax {
return nil, syserror.EINVAL
}
@@ -192,6 +199,23 @@ func (r *Registry) IPCInfo() *linux.SemInfo {
}
}
// HighestIndex returns the index of the highest used entry in
// the kernel's array.
func (r *Registry) HighestIndex() int32 {
r.mu.Lock()
defer r.mu.Unlock()
// By default, highest used index is 0 even though
// there is no semaphroe set.
var highestIndex int32
for index := range r.indexes {
if index > highestIndex {
highestIndex = index
}
}
return highestIndex
}
// RemoveID removes set with give 'id' from the registry and marks the set as
// dead. All waiters will be awakened and fail.
func (r *Registry) RemoveID(id int32, creds *auth.Credentials) error {
@@ -202,6 +226,11 @@ func (r *Registry) RemoveID(id int32, creds *auth.Credentials) error {
if set == nil {
return syserror.EINVAL
}
index, found := r.findIndexByID(id)
if !found {
// Inconsistent state.
panic(fmt.Sprintf("unable to find an index for ID: %d", id))
}
set.mu.Lock()
defer set.mu.Unlock()
@@ -213,6 +242,7 @@ func (r *Registry) RemoveID(id int32, creds *auth.Credentials) error {
}
delete(r.semaphores, set.ID)
delete(r.indexes, index)
set.destroy()
return nil
}
@@ -236,6 +266,11 @@ func (r *Registry) newSet(ctx context.Context, key int32, owner, creator fs.File
continue
}
if r.semaphores[id] == nil {
index, found := r.findFirstAvailableIndex()
if !found {
panic("unable to find an available index")
}
r.indexes[index] = id
r.lastIDUsed = id
r.semaphores[id] = set
set.ID = id
@@ -263,6 +298,24 @@ func (r *Registry) findByKey(key int32) *Set {
return nil
}
func (r *Registry) findIndexByID(id int32) (int32, bool) {
for k, v := range r.indexes {
if v == id {
return k, true
}
}
return 0, false
}
func (r *Registry) findFirstAvailableIndex() (int32, bool) {
for index := int32(0); index < setsMax; index++ {
if _, present := r.indexes[index]; !present {
return index, true
}
}
return 0, false
}
func (r *Registry) totalSems() int {
totalSems := 0
for _, v := range r.semaphores {
+4 -3
View File
@@ -150,9 +150,10 @@ func Semctl(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Syscal
buf := args[3].Pointer()
r := t.IPCNamespace().SemaphoreRegistry()
info := r.IPCInfo()
_, err := info.CopyOut(t, buf)
// TODO(gvisor.dev/issue/137): Return the index of the highest used entry.
return 0, nil, err
if _, err := info.CopyOut(t, buf); err != nil {
return 0, nil, err
}
return uintptr(r.HighestIndex()), nil, nil
case linux.SEM_INFO,
linux.SEM_STAT,
+26 -1
View File
@@ -20,6 +20,7 @@
#include <atomic>
#include <cerrno>
#include <ctime>
#include <stack>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
@@ -774,8 +775,32 @@ TEST(SemaphoreTest, SemopGetncntOnSignal_NoRandomSave) {
}
TEST(SemaphoreTest, IpcInfo) {
std::stack<int> sem_ids;
std::stack<int> max_used_indexes;
struct seminfo info;
ASSERT_THAT(semctl(0, 0, IPC_INFO, &info), SyscallSucceeds());
for (int i = 0; i < 3; i++) {
int sem_id = 0;
ASSERT_THAT(sem_id = semget(IPC_PRIVATE, 1, 0600 | IPC_CREAT),
SyscallSucceeds());
sem_ids.push(sem_id);
int max_used_index = 0;
EXPECT_THAT(max_used_index = semctl(0, 0, IPC_INFO, &info),
SyscallSucceeds());
if (!max_used_indexes.empty()) {
EXPECT_GT(max_used_index, max_used_indexes.top());
}
max_used_indexes.push(max_used_index);
}
while (!sem_ids.empty()) {
int sem_id = sem_ids.top();
sem_ids.pop();
ASSERT_THAT(semctl(sem_id, 0, IPC_RMID), SyscallSucceeds());
int max_index = max_used_indexes.top();
EXPECT_THAT(max_index = semctl(0, 0, IPC_INFO, &info), SyscallSucceeds());
EXPECT_GE(max_used_indexes.top(), max_index);
max_used_indexes.pop();
}
ASSERT_THAT(semctl(0, 0, IPC_INFO, &info), SyscallSucceedsWithValue(0));
EXPECT_EQ(info.semmap, 1024000000);
EXPECT_EQ(info.semmni, 32000);