2 * Copyright (c) 2004-2014, Haiku, Inc.
3 * Distributed under the terms of the MIT license.
7 * Axel Dörfler, axeld@pinc-software.de
8 * Paweł Dziepak, pdziepak@quarnos.org
9 * Ingo Weinhold, ingo_weinhold@gmx.de
13 #include <ksystem_info.h>
14 #include <system_info.h>
15 #include <system_revision.h>
16 #include <arch/system_info.h>
23 #include <KernelExport.h>
25 #include <AutoDeleter.h>
27 #include <block_cache.h>
32 #include <Notifications.h>
33 #include <messaging.h>
35 #include <real_time_clock.h>
40 #include <util/AutoLock.h>
42 #include <vm/vm_page.h>
45 const static int64 kKernelVersion
= 0x1;
46 const static char *kKernelName
= "kernel_" HAIKU_ARCH
;
50 dump_info(int argc
, char **argv
)
52 kprintf("kernel build: %s %s (gcc%d %s)\n", __DATE__
, __TIME__
, __GNUC__
,
54 kprintf("revision: %s\n\n", get_haiku_revision());
56 kprintf("cpu count: %" B_PRId32
"\n", smp_get_num_cpus());
58 for (int32 i
= 0; i
< smp_get_num_cpus(); i
++)
59 kprintf(" [%" B_PRId32
"] active time: %10" B_PRId64
", interrupt"
60 " time: %10" B_PRId64
", irq time: %10" B_PRId64
"\n", i
+ 1,
61 gCPU
[i
].active_time
, gCPU
[i
].interrupt_time
, gCPU
[i
].irq_time
);
63 // ToDo: Add page_faults
64 kprintf("pages:\t\t%" B_PRIuPHYSADDR
" (%" B_PRIuPHYSADDR
" max)\n",
65 vm_page_num_pages() - vm_page_num_free_pages(), vm_page_num_pages());
67 kprintf("sems:\t\t%" B_PRId32
" (%" B_PRId32
" max)\n", sem_used_sems(),
69 kprintf("ports:\t\t%" B_PRId32
" (%" B_PRId32
" max)\n", port_used_ports(),
71 kprintf("threads:\t%" B_PRId32
" (%" B_PRId32
" max)\n",
72 thread_used_threads(), thread_max_threads());
73 kprintf("teams:\t\t%" B_PRId32
" (%" B_PRId32
" max)\n", team_used_teams(),
80 // #pragma mark - user notifications
83 class SystemNotificationService
: private NotificationListener
{
85 SystemNotificationService()
87 mutex_init(&fLock
, "system notification service");
92 status_t error
= fTeamListeners
.Init();
96 error
= NotificationManager::Manager().AddListener("teams",
97 TEAM_ADDED
| TEAM_REMOVED
| TEAM_EXEC
, *this);
101 error
= NotificationManager::Manager().AddListener("threads",
102 THREAD_ADDED
| THREAD_REMOVED
| TEAM_EXEC
, *this);
109 status_t
StartListening(int32 object
, uint32 flags
, port_id port
,
112 // check the parameters
113 if ((object
< 0 && object
!= -1) || port
< 0)
116 if ((flags
& B_WATCH_SYSTEM_ALL
) == 0
117 || (flags
& ~(uint32
)B_WATCH_SYSTEM_ALL
) != 0) {
121 MutexLocker
locker(fLock
);
123 // maybe the listener already exists
124 ListenerList
* listenerList
;
125 Listener
* listener
= _FindListener(object
, port
, token
, listenerList
);
126 if (listener
!= NULL
) {
127 // just add the new flags
128 listener
->flags
|= flags
;
132 // create a new listener
133 listener
= new(std::nothrow
) Listener
;
134 if (listener
== NULL
)
136 ObjectDeleter
<Listener
> listenerDeleter(listener
);
138 listener
->port
= port
;
139 listener
->token
= token
;
140 listener
->flags
= flags
;
142 // if there's no list yet, create a new list
143 if (listenerList
== NULL
) {
144 listenerList
= new(std::nothrow
) ListenerList
;
145 if (listenerList
== NULL
)
148 listenerList
->object
= object
;
150 fTeamListeners
.Insert(listenerList
);
153 listener
->list
= listenerList
;
154 listenerList
->listeners
.Add(listener
);
155 listenerDeleter
.Detach();
157 team_associate_data(listener
);
162 status_t
StopListening(int32 object
, uint32 flags
, port_id port
,
165 MutexLocker
locker(fLock
);
168 ListenerList
* listenerList
;
169 Listener
* listener
= _FindListener(object
, port
, token
, listenerList
);
170 if (listener
== NULL
)
171 return B_ENTRY_NOT_FOUND
;
173 // clear the given flags
174 listener
->flags
&= ~flags
;
176 if (listener
->flags
!= 0)
179 team_dissociate_data(listener
);
180 _RemoveListener(listener
);
188 struct Listener
: AssociatedData
{
189 DoublyLinkedListLink
<Listener
> listLink
;
195 virtual void OwnerDeleted(AssociatedDataOwner
* owner
);
198 friend struct Listener
;
200 struct ListenerList
{
201 typedef DoublyLinkedList
<Listener
,
202 DoublyLinkedListMemberGetLink
<Listener
, &Listener::listLink
> > List
;
204 ListenerList
* hashNext
;
209 struct ListenerHashDefinition
{
210 typedef int32 KeyType
;
211 typedef ListenerList ValueType
;
213 size_t HashKey(int32 key
) const
218 size_t Hash(const ListenerList
* value
) const
220 return HashKey(value
->object
);
223 bool Compare(int32 key
, const ListenerList
* value
) const
225 return value
->object
== key
;
228 ListenerList
*& GetLink(ListenerList
* value
) const
230 return value
->hashNext
;
234 typedef BOpenHashTable
<ListenerHashDefinition
> ListenerHash
;
237 virtual void EventOccurred(NotificationService
& service
,
238 const KMessage
* event
)
240 MutexLocker
locker(fLock
);
244 if (event
->FindInt32("event", &eventCode
) != B_OK
245 || event
->FindInt32("team", &teamID
) != B_OK
) {
253 // translate the event
254 if (event
->What() == TEAM_MONITOR
) {
257 opcode
= B_TEAM_CREATED
;
258 flags
= B_WATCH_SYSTEM_TEAM_CREATION
;
261 opcode
= B_TEAM_DELETED
;
262 flags
= B_WATCH_SYSTEM_TEAM_DELETION
;
265 opcode
= B_TEAM_EXEC
;
266 flags
= B_WATCH_SYSTEM_TEAM_CREATION
267 | B_WATCH_SYSTEM_TEAM_DELETION
;
274 } else if (event
->What() == THREAD_MONITOR
) {
275 if (event
->FindInt32("thread", &object
) != B_OK
)
280 opcode
= B_THREAD_CREATED
;
281 flags
= B_WATCH_SYSTEM_THREAD_CREATION
;
284 opcode
= B_THREAD_DELETED
;
285 flags
= B_WATCH_SYSTEM_THREAD_DELETION
;
287 case THREAD_NAME_CHANGED
:
288 opcode
= B_THREAD_NAME_CHANGED
;
289 flags
= B_WATCH_SYSTEM_THREAD_PROPERTIES
;
297 // find matching listeners
298 messaging_target targets
[kMaxMessagingTargetCount
];
299 int32 targetCount
= 0;
301 _AddTargets(fTeamListeners
.Lookup(teamID
), flags
, targets
,
302 targetCount
, object
, opcode
);
303 _AddTargets(fTeamListeners
.Lookup(-1), flags
, targets
, targetCount
,
308 _SendMessage(targets
, targetCount
, object
, opcode
);
311 void _AddTargets(ListenerList
* listenerList
, uint32 flags
,
312 messaging_target
* targets
, int32
& targetCount
, int32 object
,
315 if (listenerList
== NULL
)
318 for (ListenerList::List::Iterator it
319 = listenerList
->listeners
.GetIterator();
320 Listener
* listener
= it
.Next();) {
321 if ((listener
->flags
& flags
) == 0)
324 // array is full -- need to flush it first
325 if (targetCount
== kMaxMessagingTargetCount
) {
326 _SendMessage(targets
, targetCount
, object
, opcode
);
331 targets
[targetCount
].port
= listener
->port
;
332 targets
[targetCount
++].token
= listener
->token
;
336 void _SendMessage(messaging_target
* targets
, int32 targetCount
,
337 int32 object
, uint32 opcode
)
339 // prepare the message
342 message
.SetTo(buffer
, sizeof(buffer
), B_SYSTEM_OBJECT_UPDATE
);
343 message
.AddInt32("opcode", opcode
);
344 if (opcode
< B_THREAD_CREATED
)
345 message
.AddInt32("team", object
);
347 message
.AddInt32("thread", object
);
350 send_message(message
.Buffer(), message
.ContentSize(), targets
,
354 Listener
* _FindListener(int32 object
, port_id port
, int32 token
,
355 ListenerList
*& _listenerList
)
357 _listenerList
= fTeamListeners
.Lookup(object
);
358 if (_listenerList
== NULL
)
361 for (ListenerList::List::Iterator it
362 = _listenerList
->listeners
.GetIterator();
363 Listener
* listener
= it
.Next();) {
364 if (listener
->port
== port
&& listener
->token
== token
)
371 void _RemoveObsoleteListener(Listener
* listener
)
373 MutexLocker
locker(fLock
);
374 _RemoveListener(listener
);
377 void _RemoveListener(Listener
* listener
)
379 // no flags anymore -- remove the listener
380 ListenerList
* listenerList
= listener
->list
;
381 listenerList
->listeners
.Remove(listener
);
382 listener
->ReleaseReference();
384 if (listenerList
->listeners
.IsEmpty()) {
385 // no listeners in the list anymore -- remove the list from the hash
387 fTeamListeners
.Remove(listenerList
);
393 static const int32 kMaxMessagingTargetCount
= 8;
396 ListenerHash fTeamListeners
;
399 static SystemNotificationService sSystemNotificationService
;
403 SystemNotificationService::Listener::OwnerDeleted(AssociatedDataOwner
* owner
)
405 sSystemNotificationService
._RemoveObsoleteListener(this);
409 // #pragma mark - private functions
413 count_topology_nodes(const cpu_topology_node
* node
, uint32
& count
)
416 for (int32 i
= 0; i
< node
->children_count
; i
++)
417 count_topology_nodes(node
->children
[i
], count
);
422 get_logical_processor(const cpu_topology_node
* node
)
424 while (node
->level
!= CPU_TOPOLOGY_SMT
) {
425 ASSERT(node
->children_count
> 0);
426 node
= node
->children
[0];
433 static cpu_topology_node_info
*
434 generate_topology_array(cpu_topology_node_info
* topology
,
435 const cpu_topology_node
* node
, uint32
& count
)
440 static const topology_level_type mapTopologyLevels
[] = { B_TOPOLOGY_SMT
,
441 B_TOPOLOGY_CORE
, B_TOPOLOGY_PACKAGE
, B_TOPOLOGY_ROOT
};
443 STATIC_ASSERT(sizeof(mapTopologyLevels
) / sizeof(topology_level_type
)
444 == CPU_TOPOLOGY_LEVELS
+ 1);
446 topology
->id
= node
->id
;
447 topology
->level
= node
->level
;
448 topology
->type
= mapTopologyLevels
[node
->level
];
450 arch_fill_topology_node(topology
, get_logical_processor(node
));
454 for (int32 i
= 0; i
< node
->children_count
&& count
> 0; i
++)
455 topology
= generate_topology_array(topology
, node
->children
[i
], count
);
464 get_system_info(system_info
* info
)
466 memset(info
, 0, sizeof(system_info
));
468 info
->boot_time
= rtc_boot_time();
469 info
->cpu_count
= smp_get_num_cpus();
471 vm_page_get_stats(info
);
474 info
->used_threads
= thread_used_threads();
475 info
->max_threads
= thread_max_threads();
476 info
->used_teams
= team_used_teams();
477 info
->max_teams
= team_max_teams();
478 info
->used_ports
= port_used_ports();
479 info
->max_ports
= port_max_ports();
480 info
->used_sems
= sem_used_sems();
481 info
->max_sems
= sem_max_sems();
483 info
->kernel_version
= kKernelVersion
;
484 strlcpy(info
->kernel_name
, kKernelName
, B_FILE_NAME_LENGTH
);
485 strlcpy(info
->kernel_build_date
, __DATE__
, B_OS_NAME_LENGTH
);
486 strlcpy(info
->kernel_build_time
, __TIME__
, B_OS_NAME_LENGTH
);
487 info
->abi
= B_HAIKU_ABI
;
494 get_cpu_info(uint32 firstCPU
, uint32 cpuCount
, cpu_info
* info
)
496 if (firstCPU
>= (uint32
)smp_get_num_cpus())
501 uint32 count
= std::min(cpuCount
, smp_get_num_cpus() - firstCPU
);
503 memset(info
, 0, sizeof(cpu_info
) * count
);
504 for (uint32 i
= 0; i
< count
; i
++) {
505 info
[i
].active_time
= cpu_get_active_time(firstCPU
+ i
);
506 info
[i
].enabled
= !gCPU
[firstCPU
+ i
].disabled
;
514 system_info_init(struct kernel_args
*args
)
516 add_debugger_command("info", &dump_info
, "System info");
518 return arch_system_info_init(args
);
523 system_notifications_init()
525 new (&sSystemNotificationService
) SystemNotificationService
;
527 status_t error
= sSystemNotificationService
.Init();
529 panic("system_info_init(): Failed to init system notification service");
541 _user_get_system_info(system_info
* userInfo
)
543 if (userInfo
== NULL
|| !IS_USER_ADDRESS(userInfo
))
544 return B_BAD_ADDRESS
;
547 status_t status
= get_system_info(&info
);
548 if (status
== B_OK
) {
549 if (user_memcpy(userInfo
, &info
, sizeof(system_info
)) < B_OK
)
550 return B_BAD_ADDRESS
;
560 _user_get_cpu_info(uint32 firstCPU
, uint32 cpuCount
, cpu_info
* userInfo
)
562 if (userInfo
== NULL
|| !IS_USER_ADDRESS(userInfo
))
563 return B_BAD_ADDRESS
;
564 if (firstCPU
>= (uint32
)smp_get_num_cpus())
569 uint32 count
= std::min(cpuCount
, smp_get_num_cpus() - firstCPU
);
571 cpu_info
* cpuInfos
= new(std::nothrow
) cpu_info
[count
];
572 if (cpuInfos
== NULL
)
574 ArrayDeleter
<cpu_info
> _(cpuInfos
);
576 status_t error
= get_cpu_info(firstCPU
, count
, cpuInfos
);
580 return user_memcpy(userInfo
, cpuInfos
, sizeof(cpu_info
) * count
);
585 _user_get_cpu_topology_info(cpu_topology_node_info
* topologyInfos
,
586 uint32
* topologyInfoCount
)
588 if (topologyInfoCount
== NULL
|| !IS_USER_ADDRESS(topologyInfoCount
))
589 return B_BAD_ADDRESS
;
591 const cpu_topology_node
* node
= get_cpu_topology();
594 count_topology_nodes(node
, count
);
596 if (topologyInfos
== NULL
)
597 return user_memcpy(topologyInfoCount
, &count
, sizeof(uint32
));
598 else if (!IS_USER_ADDRESS(topologyInfoCount
))
599 return B_BAD_ADDRESS
;
602 status_t error
= user_memcpy(&userCount
, topologyInfoCount
, sizeof(uint32
));
607 count
= std::min(count
, userCount
);
609 cpu_topology_node_info
* topology
610 = new(std::nothrow
) cpu_topology_node_info
[count
];
611 if (topology
== NULL
)
613 ArrayDeleter
<cpu_topology_node_info
> _(topology
);
614 memset(topology
, 0, sizeof(cpu_topology_node_info
) * count
);
616 uint32 nodesLeft
= count
;
617 generate_topology_array(topology
, node
, nodesLeft
);
618 ASSERT(nodesLeft
== 0);
620 error
= user_memcpy(topologyInfos
, topology
,
621 sizeof(cpu_topology_node_info
) * count
);
624 return user_memcpy(topologyInfoCount
, &count
, sizeof(uint32
));
629 _user_start_watching_system(int32 object
, uint32 flags
, port_id port
,
632 return sSystemNotificationService
.StartListening(object
, flags
, port
,
638 _user_stop_watching_system(int32 object
, uint32 flags
, port_id port
,
641 return sSystemNotificationService
.StopListening(object
, flags
, port
, token
);