mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Make semctl IPC_INFO cmd return the index of highest used entry.
PiperOrigin-RevId: 346973338
This commit is contained in:
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user