diff --git a/build/jam/images/HaikuImage b/build/jam/images/HaikuImage index 4b7de4a98e..0cd5a9387e 100644 --- a/build/jam/images/HaikuImage +++ b/build/jam/images/HaikuImage @@ -53,7 +53,7 @@ SYSTEM_APPS = [ FFilterByBuildFeatures SoundRecorder StyledEdit Terminal TextSearch TV WebWatch Workspaces ] ; SYSTEM_PREFERENCES = [ FFilterByBuildFeatures - Appearance Backgrounds CPUFrequency DataTranslations + Appearance Backgrounds DataTranslations Deskbar E-mail FileTypes Keyboard Keymap Locale Media Mouse Network Notifications Printers Screen ScreenSaver Shortcuts Sounds Time Touchpad Tracker VirtualMemory diff --git a/build/jam/images/HaikuImageBootstrap b/build/jam/images/HaikuImageBootstrap index 2cde49320e..7d54d16a06 100644 --- a/build/jam/images/HaikuImageBootstrap +++ b/build/jam/images/HaikuImageBootstrap @@ -53,7 +53,7 @@ SYSTEM_APPS = [ FFilterByBuildFeatures StyledEdit Terminal TextSearch Workspaces ] ; SYSTEM_PREFERENCES = [ FFilterByBuildFeatures - Appearance Backgrounds CPUFrequency + Appearance Backgrounds Deskbar FileTypes Keyboard Keymap Locale Mouse Network Notifications Screen ScreenSaver Shortcuts Time Touchpad Tracker VirtualMemory diff --git a/build/jam/packages/Haiku b/build/jam/packages/Haiku index 6cf4eceb6f..2d206bd870 100644 --- a/build/jam/packages/Haiku +++ b/build/jam/packages/Haiku @@ -52,6 +52,8 @@ AddFilesToPackage add-ons kernel generic AddFilesToPackage add-ons kernel partitioning_systems : amiga_rdb apple efi_gpt intel session ; AddFilesToPackage add-ons kernel interrupt_controllers : openpic@ppc ; +AddFilesToPackage add-ons kernel power cpufreq : intel_pstates@x86,x86_64 ; +AddFilesToPackage add-ons kernel power cpuidle : intel_cstates@x86,x86_64 ; if $(TARGET_ARCH) = x86 || $(TARGET_ARCH) = x86_64 { AddFilesToPackage add-ons kernel cpu : generic_x86 ; @@ -60,7 +62,6 @@ if $(TARGET_ARCH) = x86 || $(TARGET_ARCH) = x86_64 { # drivers AddNewDriversToPackage disk scsi : scsi_cd scsi_disk ; AddNewDriversToPackage disk virtual : virtio_block ; -AddNewDriversToPackage power : enhanced_speedstep@x86 ; AddNewDriversToPackage power : $(SYSTEM_ADD_ONS_DRIVERS_POWER) ; #AddNewDriversToPackage display : display_controls@x86 ; diff --git a/build/jam/packages/HaikuBootstrap b/build/jam/packages/HaikuBootstrap index 0f092508d0..c22766bb7a 100644 --- a/build/jam/packages/HaikuBootstrap +++ b/build/jam/packages/HaikuBootstrap @@ -51,6 +51,8 @@ AddFilesToPackage add-ons kernel generic AddFilesToPackage add-ons kernel partitioning_systems : amiga_rdb apple efi_gpt intel session ; AddFilesToPackage add-ons kernel interrupt_controllers : openpic@ppc ; +AddFilesToPackage add-ons kernel power cpufreq : intel_pstates@x86,x86_64 ; +AddFilesToPackage add-ons kernel power cpuidle : intel_cstates@x86,x86_64 ; if $(TARGET_ARCH) = x86 || $(TARGET_ARCH) = x86_64 { AddFilesToPackage add-ons kernel cpu : generic_x86 ; @@ -59,7 +61,6 @@ if $(TARGET_ARCH) = x86 || $(TARGET_ARCH) = x86_64 { # drivers AddNewDriversToPackage disk scsi : scsi_cd scsi_disk ; AddNewDriversToPackage disk virtual : virtio_block ; -AddNewDriversToPackage power : enhanced_speedstep@x86 ; AddNewDriversToPackage power : acpi_battery@x86 ; #AddNewDriversToPackage display : display_controls@x86 ; diff --git a/data/catalogs/preferences/cpufrequency/be.catkeys b/data/catalogs/preferences/cpufrequency/be.catkeys deleted file mode 100644 index 3c09cb3f55..0000000000 --- a/data/catalogs/preferences/cpufrequency/be.catkeys +++ /dev/null @@ -1,21 +0,0 @@ -1 belarusian x-vnd.Haiku-CPUFrequencyPref 1007318924 -Ok Status view Так -CPU frequency status view CPU Frequency View Паказнік стану частаты працэсара -OK Status view ОК -Set state Status view Пазначыць стан -Defaults Pref Window Прадвызначаныя -Install replicant into Deskbar CPU Frequency View Усталяваць рэплікант у Deskbar -Quit Status view Выйсце -High performance Status view Вышэйшая прадукцыйнасць -Stepping policy CPU Frequency View Палітыка пакрокавай рэгуляцыі -Dynamic performance Status view Дынамічная прадукцыйнасць -Step up by CPU usage Color Step View Актывізаваць у залежнасьці ад занятасці працэсара -Dynamic stepping CPU Frequency View Дынамічны рэжым пакрокавай рэгуляцыі -Stepping policy: CPU Frequency View Палітыка пакрокавай рэгуляцыі: -Integration time [ms]: CPU Frequency View Квант інтэграцыі [ms]: -Open Speedstep preferences… Status view Паказаць наладкі Speedstep… -Revert Pref Window Вярнуць -Low energy Status view Экономия энергии -Launching the CPU frequency preflet failed.\n\nError: Status view Немагчыма запусціць канфігурацыйную праграму!\n\nКод памылкі: -CPUFrequency\n\twritten by Clemens Zeidler\n\tCopyright 2009, Haiku, Inc.\n Status view CPU Frequency\n\tбыў распрацаваны Clemens Zeidler\n\tCopyright 2009, Haiku, Inc.\n -CPUFrequency System name Частата Працэсара diff --git a/data/catalogs/preferences/cpufrequency/bg.catkeys b/data/catalogs/preferences/cpufrequency/bg.catkeys deleted file mode 100644 index 763d7c4ea3..0000000000 --- a/data/catalogs/preferences/cpufrequency/bg.catkeys +++ /dev/null @@ -1,18 +0,0 @@ -1 bulgarian x-vnd.Haiku-CPUFrequencyPref 1018039204 -Ok Status view Ок -CPU frequency status view CPU Frequency View Статус на CPU честотата -Set state Status view Изберете състояние -Defaults Pref Window По подразбиране -Install replicant into Deskbar CPU Frequency View Инсталирай репликант в Deskbar -High performance Status view Висока производителност -Stepping policy CPU Frequency View Постъпково изменение на частотата на CPU -Dynamic performance Status view Динамична производителност -Step up by CPU usage Color Step View Стъпка на производителност на CPU: -Dynamic stepping CPU Frequency View Динамично изменение -Stepping policy: CPU Frequency View Постъпково изменение на частотата на CPU: -Integration time [ms]: CPU Frequency View Време на интеграция [мс]: -Open Speedstep preferences… Status view Отвори постъпковите настройки -Revert Pref Window Върни -Low energy Status view Икономия на енергия -Launching the CPU frequency preflet failed.\n\nError: Status view Старта на CPU Frequency не се състоя.\n\nГрешка: -CPUFrequency\n\twritten by Clemens Zeidler\n\tCopyright 2009, Haiku, Inc.\n Status view CPUFrequency\n\tе разработен от Clemens Zeidler\n\tCopyright 2009, Haiku, Inc.\n diff --git a/data/catalogs/preferences/cpufrequency/cs.catkeys b/data/catalogs/preferences/cpufrequency/cs.catkeys deleted file mode 100644 index 647de76f32..0000000000 --- a/data/catalogs/preferences/cpufrequency/cs.catkeys +++ /dev/null @@ -1,19 +0,0 @@ -1 czech x-vnd.Haiku-CPUFrequencyPref 3974849433 -CPU frequency status view CPU Frequency View Zobrazení statusu frekvence CPU -CPUFrequency\n\twritten by Clemens Zeidler\n\tCopyright 2009, Haiku, Inc.\n Status view CPUFrequency\n\tnapsal Clemens Zeidler\n\tCopyright 2009, Haiku, Inc.\n -Defaults Pref Window Původní -Dynamic performance Status view Dynamický výkon -Dynamic stepping CPU Frequency View Dynamické krokování -High performance Status view Vysoký výkon -Install replicant into Deskbar CPU Frequency View Instaloval replikant do Deskbaru -Integration time [ms]: CPU Frequency View Integrační čas [ms]: -Launching the CPU frequency preflet failed.\n\nError: Status view Nepodařilo se otevřít nastavení frekvence CPU.\n\nChyba: -Low energy Status view Nízká spotřeba -Ok Status view Ok -Open Speedstep preferences… Status view Otevřít nastavení SpeedStep... -Quit Status view Odejít -Revert Pref Window Obnovit -Set state Status view Nastavit stav -Step up by CPU usage Color Step View Krokovat podle využití CPU -Stepping policy CPU Frequency View Krokovací politika -Stepping policy: CPU Frequency View Krokovací politika: diff --git a/data/catalogs/preferences/cpufrequency/da.catkeys b/data/catalogs/preferences/cpufrequency/da.catkeys deleted file mode 100644 index 228fa1028a..0000000000 --- a/data/catalogs/preferences/cpufrequency/da.catkeys +++ /dev/null @@ -1,19 +0,0 @@ -1 danish x-vnd.Haiku-CPUFrequencyPref 3974849433 -CPU frequency status view CPU Frequency View CPU frekvens statusoversigt -CPUFrequency\n\twritten by Clemens Zeidler\n\tCopyright 2009, Haiku, Inc.\n Status view CPUFrekvens\n\tskrevet af Clemens Zeidler\n\tOphavsret 2009, Haiku, Inc.\n -Defaults Pref Window Standard indstillinger -Dynamic performance Status view Dynamisk ydeevne -Dynamic stepping CPU Frequency View Dynamisk acceleration -High performance Status view Høj ydeevne -Install replicant into Deskbar CPU Frequency View Indsæt replikant i Deskbar -Integration time [ms]: CPU Frequency View Integrationstid [ms]: -Launching the CPU frequency preflet failed.\n\nError: Status view Det var ikke muligt at starte CPU frekvens indstillings programmet.\n\nFejl: -Low energy Status view Lavt energiforbrug -Ok Status view OK -Open Speedstep preferences… Status view Åben Speedstep egenskaber… -Quit Status view Afslut -Revert Pref Window Tilbagestil -Set state Status view Sæt tilstand -Step up by CPU usage Color Step View Acceleration efter CPU belastning -Stepping policy CPU Frequency View Accelerationspolitik -Stepping policy: CPU Frequency View Accelerationspolitik: diff --git a/data/catalogs/preferences/cpufrequency/de.catkeys b/data/catalogs/preferences/cpufrequency/de.catkeys deleted file mode 100644 index 153a6e4ed5..0000000000 --- a/data/catalogs/preferences/cpufrequency/de.catkeys +++ /dev/null @@ -1,21 +0,0 @@ -1 german x-vnd.Haiku-CPUFrequencyPref 1007318924 -Ok Status view OK -CPU frequency status view CPU Frequency View CPU-Takt-Anzeige -OK Status view OK -Set state Status view Fester Takt -Defaults Pref Window Standardwerte -Install replicant into Deskbar CPU Frequency View Replikant in Deskbar installieren -Quit Status view Beenden -High performance Status view Hohe Leistung -Stepping policy CPU Frequency View Taktungsrichtlinie -Dynamic performance Status view Dynamische Leistung -Step up by CPU usage Color Step View Taktänderung ab CPU-Auslastung von: -Dynamic stepping CPU Frequency View Dynamische Taktung -Stepping policy: CPU Frequency View Taktungsrichtlinie: -Integration time [ms]: CPU Frequency View Messintervall [ms]: -Open Speedstep preferences… Status view Speedstep Einstellungen öffnen… -Revert Pref Window Anfangswerte -Low energy Status view Geringer Energieverbrauch -Launching the CPU frequency preflet failed.\n\nError: Status view Das CPU-Takt-Preflet konnte nicht gestartet werden.\n\nFehler: -CPUFrequency\n\twritten by Clemens Zeidler\n\tCopyright 2009, Haiku, Inc.\n Status view CPU-Takt\n\tGeschrieben von Clemens Zeidler.\n\tCopyright 2009, Haiku, Inc.\n -CPUFrequency System name CPU-Takt diff --git a/data/catalogs/preferences/cpufrequency/el.catkeys b/data/catalogs/preferences/cpufrequency/el.catkeys deleted file mode 100644 index 162b3e7df8..0000000000 --- a/data/catalogs/preferences/cpufrequency/el.catkeys +++ /dev/null @@ -1,20 +0,0 @@ -1 greek, modern (1453-) x-vnd.Haiku-CPUFrequencyPref 3079996868 -Ok Status view Εντάξει -CPU frequency status view CPU Frequency View Συχνότητα επεξεργαστή προβολή κατάστασης -Set state Status view Ορισμός κατάστασης -Defaults Pref Window Προεπιλογές -Install replicant into Deskbar CPU Frequency View Εγκατάσταση αντίγραφου στη Μπάρα εργασιών -Quit Status view Έξοδος -High performance Status view Υψηλή επίδοση -Stepping policy CPU Frequency View Πολιτική βηματισμού -Dynamic performance Status view Δυναμική επίδοση -Step up by CPU usage Color Step View Αύξηση με χρήση της CPU -Dynamic stepping CPU Frequency View Δυναμικός βηματισμός -Stepping policy: CPU Frequency View Πολιτική βηματισμού: -Integration time [ms]: CPU Frequency View Χρόνος ολοκλήρωσης [ms]: -Open Speedstep preferences… Status view Άνοιγμα προτιμήσεων Ταχύτητα βήματος -Revert Pref Window Επαναφορά -Low energy Status view Χαμηλή ενέργεια -Launching the CPU frequency preflet failed.\n\nError: Status view Απέτυχε η εκκίνηση του preflet Συχνότητα επεξεργαστή.\n\nΣφάλμα: -CPUFrequency\n\twritten by Clemens Zeidler\n\tCopyright 2009, Haiku, Inc.\n Status view Συχνότητα Επεξεργαστή\n\tγράφτηκε από τον Clemens Zeidler\n\tΠνευματικά δικαιώματα 2009, Haiku, Inc.\n -CPUFrequency System name Συχνότητα της CPU diff --git a/data/catalogs/preferences/cpufrequency/eo.catkeys b/data/catalogs/preferences/cpufrequency/eo.catkeys deleted file mode 100644 index 0d1720550b..0000000000 --- a/data/catalogs/preferences/cpufrequency/eo.catkeys +++ /dev/null @@ -1,19 +0,0 @@ -1 esperanto x-vnd.Haiku-CPUFrequencyPref 3974849433 -CPU frequency status view CPU Frequency View Procesorofteca stato -CPUFrequency\n\twritten by Clemens Zeidler\n\tCopyright 2009, Haiku, Inc.\n Status view Procesorofteco\n\tskribita per Clemens Zeidler\n\tCopyright 2009, Haiku, Inc.\n -Defaults Pref Window Aprioraj -Dynamic performance Status view Dinamika rendimento -Dynamic stepping CPU Frequency View Dinamika akcelo -High performance Status view Plejbona rendimento -Install replicant into Deskbar CPU Frequency View Instali la kopianton en la Deskbar-on -Integration time [ms]: CPU Frequency View Integralada tempo [ms]: -Launching the CPU frequency preflet failed.\n\nError: Status view Malsukcesis lanĉi la procesorofteca prefileto.\n\nEraro: -Low energy Status view Malgranda energio -Ok Status view Bone -Open Speedstep preferences… Status view Malfermi la Speedstep-ajn agordojn… -Quit Status view Eliri -Revert Pref Window Malfari -Set state Status view Ŝanĝi staton -Step up by CPU usage Color Step View Akcelo per procesora uzo: -Stepping policy CPU Frequency View Akcela reĝimo -Stepping policy: CPU Frequency View Akcela reĝimo: diff --git a/data/catalogs/preferences/cpufrequency/fi.catkeys b/data/catalogs/preferences/cpufrequency/fi.catkeys deleted file mode 100644 index d75dd8d3b6..0000000000 --- a/data/catalogs/preferences/cpufrequency/fi.catkeys +++ /dev/null @@ -1,21 +0,0 @@ -1 finnish x-vnd.Haiku-CPUFrequencyPref 1007318924 -Ok Status view Valmis -CPU frequency status view CPU Frequency View Suoritintaajuuden tilanäkymä -OK Status view Valmis -Set state Status view Aseta tila -Defaults Pref Window Oletukset -Install replicant into Deskbar CPU Frequency View Asenna kopio Työpöytäpalkkiin -Quit Status view Poistu -High performance Status view Korkea suorituskyky -Stepping policy CPU Frequency View Muutostapa -Dynamic performance Status view Dynaaminen suorituskyky -Step up by CPU usage Color Step View Muuta ylöspäin tämän suorittimen käyttömäärän kohdalla: -Dynamic stepping CPU Frequency View Dynaaminen muutos -Stepping policy: CPU Frequency View Muutostapa: -Integration time [ms]: CPU Frequency View Integraatioaika [ms]: -Open Speedstep preferences… Status view Avaa nopeusaskelvalinnat... -Revert Pref Window Palauta -Low energy Status view Matala energiankulutus -Launching the CPU frequency preflet failed.\n\nError: Status view Suoritintaajuuden asetusohjelman käynnistys epäonnistui.\n\nVirhe: -CPUFrequency\n\twritten by Clemens Zeidler\n\tCopyright 2009, Haiku, Inc.\n Status view Suoritintaajuusasetukset\n\t tekijä: Clemens Zeidler\n\t Copyright 2009, Haiku, Inc.\n -CPUFrequency System name Suoritintaajuusasetukset diff --git a/data/catalogs/preferences/cpufrequency/fr.catkeys b/data/catalogs/preferences/cpufrequency/fr.catkeys deleted file mode 100644 index b0dbc2f29d..0000000000 --- a/data/catalogs/preferences/cpufrequency/fr.catkeys +++ /dev/null @@ -1,21 +0,0 @@ -1 french x-vnd.Haiku-CPUFrequencyPref 1007318924 -Ok Status view Ok -CPU frequency status view CPU Frequency View Vue de l'état de la fréquence du CPU -OK Status view OK -Set state Status view Changer l'état -Defaults Pref Window Par défauts -Install replicant into Deskbar CPU Frequency View Installer le réplicant dans la Deskbar -Quit Status view Quitter -High performance Status view Haute performance -Stepping policy CPU Frequency View Stratégie d'accélération -Dynamic performance Status view Performance dynamique -Step up by CPU usage Color Step View Accélération selon l'activité CPU -Dynamic stepping CPU Frequency View Accélération dynamique -Stepping policy: CPU Frequency View Stratégie d'accélération : -Integration time [ms]: CPU Frequency View Temps d'intégration [ms] : -Open Speedstep preferences… Status view Ouvrir les préférences Speestep… -Revert Pref Window Rétablir -Low energy Status view Basse consommation -Launching the CPU frequency preflet failed.\n\nError: Status view Échec de lancement des préférences de fréquence du CPU.\n\nErreur : -CPUFrequency\n\twritten by Clemens Zeidler\n\tCopyright 2009, Haiku, Inc.\n Status view Fréquence CPU\n\tÉcrit par Clemens Zeidler\n\tCopyright 2009, Haiku, Inc.\n -CPUFrequency System name Fréquence CPU diff --git a/data/catalogs/preferences/cpufrequency/hi.catkeys b/data/catalogs/preferences/cpufrequency/hi.catkeys deleted file mode 100644 index 9911779ae4..0000000000 --- a/data/catalogs/preferences/cpufrequency/hi.catkeys +++ /dev/null @@ -1,20 +0,0 @@ -1 hindi x-vnd.Haiku-CPUFrequencyPref 3079996868 -Ok Status view ठीक है -CPU frequency status view CPU Frequency View सीपियु आवृत्ति स्थिति देखने के लिए -Set state Status view सेट स्टेट -Defaults Pref Window डिफ़ॉल्ट्स -Install replicant into Deskbar CPU Frequency View डेस्कबार में स्थापित रेप्लिका -Quit Status view छोड़ना -High performance Status view उच्च निष्पादन -Stepping policy CPU Frequency View कदम नीति -Dynamic performance Status view गतिशील प्रदर्शन -Step up by CPU usage Color Step View धीरे-धीरे सीपियु का उपयोग द्वारा चरण होना -Dynamic stepping CPU Frequency View गतिशील कदम -Stepping policy: CPU Frequency View कदम नीति: -Integration time [ms]: CPU Frequency View एकीकरण समय [एमएस]: -Open Speedstep preferences… Status view खुला स्पीद्स्तेप वरीयता ... -Revert Pref Window पलटें -Low energy Status view कम इनरजी -Launching the CPU frequency preflet failed.\n\nError: Status view लौन्चिंग सीपियु आवृत्ति शुभारंभ विफल.\n\nत्रुटि: -CPUFrequency\n\twritten by Clemens Zeidler\n\tCopyright 2009, Haiku, Inc.\n Status view सीपियु रेक़ुएन्क्य\n\t क्लेमेंस ज़िल्डर द्वारा त्व्रित्तें\n\t कोप्य्रिघ्त 2009, हाइकू, Inc.\n -CPUFrequency System name सीपियु की आवृत्ति diff --git a/data/catalogs/preferences/cpufrequency/hr.catkeys b/data/catalogs/preferences/cpufrequency/hr.catkeys deleted file mode 100644 index aa1f020eec..0000000000 --- a/data/catalogs/preferences/cpufrequency/hr.catkeys +++ /dev/null @@ -1,12 +0,0 @@ -1 croatian x-vnd.Haiku-CPUFrequencyPref 2355894194 -CPU frequency status view CPU Frequency View Pogled stanja frekvencije procesora -CPUFrequency\n\twritten by Clemens Zeidler\n\tCopyright 2009, Haiku, Inc.\n Status view Frekvencija procesora\n\tnapisao Clemens Zeidler\n\tAutoraska prava 2009, Haiku, Inc.\n -Defaults Pref Window Zadano -Dynamic performance Status view Dinamične performanse -High performance Status view Visoke performanse -Integration time [ms]: CPU Frequency View Vrijeme integracije [ms]: -Ok Status view U redu -Open Speedstep preferences… Status view Otvori Speedstep osobitosti... -Quit Status view Isključi -Revert Pref Window Preokreni -Set state Status view Postavi stanje diff --git a/data/catalogs/preferences/cpufrequency/hu.catkeys b/data/catalogs/preferences/cpufrequency/hu.catkeys deleted file mode 100644 index da469078c7..0000000000 --- a/data/catalogs/preferences/cpufrequency/hu.catkeys +++ /dev/null @@ -1,21 +0,0 @@ -1 hungarian x-vnd.Haiku-CPUFrequencyPref 1007318924 -Ok Status view Rendben -CPU frequency status view CPU Frequency View Processzor-frekvencia állapota -OK Status view Rendben -Set state Status view Órajel beállítása -Defaults Pref Window Eredeti -Install replicant into Deskbar CPU Frequency View Replikáns telepítése az Asztalsávba -Quit Status view Kilépés -High performance Status view Nagy teljesítmény -Stepping policy CPU Frequency View Fokozatszabályozás -Dynamic performance Status view Dinamikus teljesítmény -Step up by CPU usage Color Step View Kiegyensúlyozott teljesítmény -Dynamic stepping CPU Frequency View Szabadon választható fokozatok -Stepping policy: CPU Frequency View Fokozatszabályozás: -Integration time [ms]: CPU Frequency View Alkalmazkodás ideje [ms]: -Open Speedstep preferences… Status view Fokozatszabályozási beállító megnyitása… -Revert Pref Window Visszaállít -Low energy Status view Alacsony energiafogyasztás -Launching the CPU frequency preflet failed.\n\nError: Status view Nem sikerült a Processzor-frekvencia elindítása.\n\nHiba: -CPUFrequency\n\twritten by Clemens Zeidler\n\tCopyright 2009, Haiku, Inc.\n Status view Processzor-frekvencia\n\tÍrta: Clemens Zeidler\n\tCopyright 2009, Haiku, Inc.\n -CPUFrequency System name Processzor-frekvencia diff --git a/data/catalogs/preferences/cpufrequency/it.catkeys b/data/catalogs/preferences/cpufrequency/it.catkeys deleted file mode 100644 index dbbc4b643b..0000000000 --- a/data/catalogs/preferences/cpufrequency/it.catkeys +++ /dev/null @@ -1,19 +0,0 @@ -1 italian x-vnd.Haiku-CPUFrequencyPref 3974849433 -CPU frequency status view CPU Frequency View Stato frequenza della CPU -CPUFrequency\n\twritten by Clemens Zeidler\n\tCopyright 2009, Haiku, Inc.\n Status view Frequenza CPU\n\tscritto da Clemens Zeidler\n\tDiritti d'autore ©2009, Haiku, Inc.\n -Defaults Pref Window Predefiniti -Dynamic performance Status view Prestazioni dinamiche -Dynamic stepping CPU Frequency View Scalabilità dinamica -High performance Status view Prestazioni elevate -Install replicant into Deskbar CPU Frequency View Installa il replicante nella Deskbar -Integration time [ms]: CPU Frequency View Tempo di intervento [ms]: -Launching the CPU frequency preflet failed.\n\nError: Status view Impossibile far partire le preferenze frequenza CPU.\n\nErrore: -Low energy Status view Bassi consumi -Ok Status view Ok -Open Speedstep preferences… Status view Apri preferenze Speedstep… -Quit Status view Esci -Revert Pref Window Ripristina -Set state Status view Imposta stato -Step up by CPU usage Color Step View Scala in base all'utilizzo della CPU -Stepping policy CPU Frequency View Regole di scalabilità -Stepping policy: CPU Frequency View Regola scalabilità: diff --git a/data/catalogs/preferences/cpufrequency/ja.catkeys b/data/catalogs/preferences/cpufrequency/ja.catkeys deleted file mode 100644 index cd225eb8a4..0000000000 --- a/data/catalogs/preferences/cpufrequency/ja.catkeys +++ /dev/null @@ -1,21 +0,0 @@ -1 japanese x-vnd.Haiku-CPUFrequencyPref 1007318924 -Ok Status view Ok -CPU frequency status view CPU Frequency View CPU 周波数ビュー -OK Status view OK -Set state Status view 設定 -Defaults Pref Window デフォルト -Install replicant into Deskbar CPU Frequency View レプリカントを Deskbar に表示 -Quit Status view 終了 -High performance Status view ハイパフォーマンス -Stepping policy CPU Frequency View ステッピングポリシー -Dynamic performance Status view ダイナミックパフォーマンス -Step up by CPU usage Color Step View CPU 負荷に応じてステップアップ -Dynamic stepping CPU Frequency View ダイナミックステッピング -Stepping policy: CPU Frequency View ステッピングポリシー -Integration time [ms]: CPU Frequency View 積分時間 [ms]: -Open Speedstep preferences… Status view Open Speedstep の設定… -Revert Pref Window 元に戻す -Low energy Status view 省電力モード -Launching the CPU frequency preflet failed.\n\nError: Status view CPU 周波数の起動に失敗しました。\n\nエラー: -CPUFrequency\n\twritten by Clemens Zeidler\n\tCopyright 2009, Haiku, Inc.\n Status view CPU 周波数\n\tClemens Zeidler 作\n\tCopyright 2009, Haiku, Inc.\n -CPUFrequency System name CPU 周波数 diff --git a/data/catalogs/preferences/cpufrequency/ko.catkeys b/data/catalogs/preferences/cpufrequency/ko.catkeys deleted file mode 100644 index da3fcad2cb..0000000000 --- a/data/catalogs/preferences/cpufrequency/ko.catkeys +++ /dev/null @@ -1,19 +0,0 @@ -1 korean x-vnd.Haiku-CPUFrequencyPref 3974849433 -CPU frequency status view CPU Frequency View CPU 주파수 상태 보기 -CPUFrequency\n\twritten by Clemens Zeidler\n\tCopyright 2009, Haiku, Inc.\n Status view CPU주파수\n\tClemens Zeidler 작성\n\t저작권 2009, Haiku, Inc.\n -Defaults Pref Window 기본설정 -Dynamic performance Status view 동적 성능 -Dynamic stepping CPU Frequency View 동적 스테핑 -High performance Status view 고성능 -Install replicant into Deskbar CPU Frequency View 데스크바에 복제품 설치 -Integration time [ms]: CPU Frequency View 통합 시간 [ms]: -Launching the CPU frequency preflet failed.\n\nError: Status view CPU 주파수 제어판 불러오기 실패.\n\n에러: -Low energy Status view 저전력 -Ok Status view 확인 -Open Speedstep preferences… Status view 스피드스텝 설정 열기… -Quit Status view 나가기 -Revert Pref Window 되돌리기 -Set state Status view 상태 설정 -Step up by CPU usage Color Step View CPU 사용량에 따라 증가 -Stepping policy CPU Frequency View 스테핑 정책 -Stepping policy: CPU Frequency View 스테핑 정책: diff --git a/data/catalogs/preferences/cpufrequency/lt.catkeys b/data/catalogs/preferences/cpufrequency/lt.catkeys deleted file mode 100644 index 7e8f75462c..0000000000 --- a/data/catalogs/preferences/cpufrequency/lt.catkeys +++ /dev/null @@ -1,21 +0,0 @@ -1 lithuanian x-vnd.Haiku-CPUFrequencyPref 1007318924 -Ok Status view Gerai -CPU frequency status view CPU Frequency View Centrinio procesoriaus dažnio indikatorius -OK Status view Gerai -Set state Status view Pasirinkta būsena -Defaults Pref Window Numatytai -Install replicant into Deskbar CPU Frequency View Patalpinti indikatorių pranešimų srityje -Quit Status view Baigti darbą -High performance Status view Didelis našumas -Stepping policy CPU Frequency View Centrinio procesoriaus veiksena -Dynamic performance Status view Prisitaikantis našumas -Step up by CPU usage Color Step View Našumo keitimo žingsnis -Dynamic stepping CPU Frequency View Prisitaikančio našumo derinimas -Stepping policy: CPU Frequency View Centrinio procesoriaus veiksena: -Integration time [ms]: CPU Frequency View Integravimosi laikas [ms]: -Open Speedstep preferences… Status view CP dažnio nuostatos… -Revert Pref Window Atšaukti pakeitimus -Low energy Status view Energijos taupymas -Launching the CPU frequency preflet failed.\n\nError: Status view Nepavyko atverti Centrinio procesoriaus dažnio nuostatų lango.\n\nKlaida: -CPUFrequency\n\twritten by Clemens Zeidler\n\tCopyright 2009, Haiku, Inc.\n Status view Centrinio procesoriaus dažnis\n\tsukurtas Clemens'o Zeidler'io\n\t© 2009, Haiku, Inc.\n -CPUFrequency System name Centrinio procesoriaus dažnis diff --git a/data/catalogs/preferences/cpufrequency/nb.catkeys b/data/catalogs/preferences/cpufrequency/nb.catkeys deleted file mode 100644 index 3a594c7606..0000000000 --- a/data/catalogs/preferences/cpufrequency/nb.catkeys +++ /dev/null @@ -1,19 +0,0 @@ -1 bokmål, norwegian; norwegian bokmål x-vnd.Haiku-CPUFrequencyPref 1579805342 -Ok Status view OK -CPU frequency status view CPU Frequency View Visning av CPU-status -Set state Status view Sett tilstand -Defaults Pref Window Standardinnstillinger -Install replicant into Deskbar CPU Frequency View Installer replikanten i Deskbar -Quit Status view Avslutt -High performance Status view Høy ytelse -Stepping policy CPU Frequency View Stepping-policy -Dynamic performance Status view Dynamisk ytelse -Dynamic stepping CPU Frequency View Dynamisk stepping -Stepping policy: CPU Frequency View Stepping-policy -Integration time [ms]: CPU Frequency View Integrasjonstid [ms]: -Open Speedstep preferences… Status view Åpne Speedstep-innstillinger -Revert Pref Window Tilbakestill -Low energy Status view Lavenergi -Launching the CPU frequency preflet failed.\n\nError: Status view Feil ved lasting av Prosessorhastighet. \n\nFeil: -CPUFrequency\n\twritten by Clemens Zeidler\n\tCopyright 2009, Haiku, Inc.\n Status view CPUFrequency\n\tskrevet av Clemens Zeidler\n\tOpphavsrett 2009, Haiku, Inc.\n -CPUFrequency System name Prosessorhastighet diff --git a/data/catalogs/preferences/cpufrequency/nl.catkeys b/data/catalogs/preferences/cpufrequency/nl.catkeys deleted file mode 100644 index 4367c89acb..0000000000 --- a/data/catalogs/preferences/cpufrequency/nl.catkeys +++ /dev/null @@ -1,21 +0,0 @@ -1 dutch; flemish x-vnd.Haiku-CPUFrequencyPref 1007318924 -Ok Status view Oké -CPU frequency status view CPU Frequency View Weergave CPU-frequentiestatus -OK Status view Ok -Set state Status view Toestand instellen -Defaults Pref Window Standaardwaarden -Install replicant into Deskbar CPU Frequency View Replicant in Deskbar installeren -Quit Status view Afsluiten -High performance Status view Hoge prestaties -Stepping policy CPU Frequency View Stapbeleid -Dynamic performance Status view Dynamische prestaties -Step up by CPU usage Color Step View Opvoeren door CPU-gebruik -Dynamic stepping CPU Frequency View Dynamisch opvoeren -Stepping policy: CPU Frequency View Opvoerbeleid: -Integration time [ms]: CPU Frequency View Integratietijd [ms]: -Open Speedstep preferences… Status view Speedstep-voorkeuren openen… -Revert Pref Window Herstellen -Low energy Status view Lage energie -Launching the CPU frequency preflet failed.\n\nError: Status view Starten van de CPU-frequentiepreflet is mislukt.\n\nFout: -CPUFrequency\n\twritten by Clemens Zeidler\n\tCopyright 2009, Haiku, Inc.\n Status view CPUFrequency\n\tdoor Clemens Zeidler\n\tCopyright 2009, Haiku, Inc.\n -CPUFrequency System name CPUFrequency diff --git a/data/catalogs/preferences/cpufrequency/pl.catkeys b/data/catalogs/preferences/cpufrequency/pl.catkeys deleted file mode 100644 index 1cba58892d..0000000000 --- a/data/catalogs/preferences/cpufrequency/pl.catkeys +++ /dev/null @@ -1,21 +0,0 @@ -1 polish x-vnd.Haiku-CPUFrequencyPref 1007318924 -Ok Status view Ok -CPU frequency status view CPU Frequency View Widok statusu częstotliwości taktowania procesora -OK Status view OK -Set state Status view Ustaw stan -Defaults Pref Window Przywróć ustawienia domyślne -Install replicant into Deskbar CPU Frequency View Zainstaluj replikant na Panelu Pulpitu -Quit Status view Zamknij -High performance Status view Wysoka wydajność -Stepping policy CPU Frequency View Polityka skalowania procesora -Dynamic performance Status view Dynamicznie dopasowana wydajność -Step up by CPU usage Color Step View Ustawiaj taktowanie w zależności od obciążenia procesora -Dynamic stepping CPU Frequency View Dynamiczne skalowanie -Stepping policy: CPU Frequency View Polityka skalowania: -Integration time [ms]: CPU Frequency View Czas integracji (w milisekundach): -Open Speedstep preferences… Status view Otwórz ustawienia Speedstep… -Revert Pref Window Przywróć poprzednie ustawienia -Low energy Status view Oszczędna -Launching the CPU frequency preflet failed.\n\nError: Status view Uruchomienie prefletu częstotliwości procesora zakończyło się niepowodzeniem.\n\nBłąd: -CPUFrequency\n\twritten by Clemens Zeidler\n\tCopyright 2009, Haiku, Inc.\n Status view CPUFrequency\n\tnapisane przez Clemensa Zeidlera\n\tCopyright 2009, Haiku, Inc.\n -CPUFrequency System name Częstotliwość procesora diff --git a/data/catalogs/preferences/cpufrequency/pt.catkeys b/data/catalogs/preferences/cpufrequency/pt.catkeys deleted file mode 100644 index ae2db82ce7..0000000000 --- a/data/catalogs/preferences/cpufrequency/pt.catkeys +++ /dev/null @@ -1,12 +0,0 @@ -1 portuguese x-vnd.Haiku-CPUFrequencyPref 2133997991 -Defaults Pref Window Predefenições -Dynamic stepping CPU Frequency View Aceleração Dinâmica -Install replicant into Deskbar CPU Frequency View Instalar o Replicant na Deskbar -Integration time [ms]: CPU Frequency View Tempo de integração [ms]: -Ok Status view OK -Quit Status view Sair -Revert Pref Window Reverter -Set state Status view Defenir estado -Step up by CPU usage Color Step View Variação de velocidade com base no uso do CPU -Stepping policy CPU Frequency View Política de Aceleração -Stepping policy: CPU Frequency View Política de Aceleração: diff --git a/data/catalogs/preferences/cpufrequency/pt_BR.catkeys b/data/catalogs/preferences/cpufrequency/pt_BR.catkeys deleted file mode 100644 index 6744324be8..0000000000 --- a/data/catalogs/preferences/cpufrequency/pt_BR.catkeys +++ /dev/null @@ -1,21 +0,0 @@ -1 portuguese (brazil) x-vnd.Haiku-CPUFrequencyPref 1007318924 -Ok Status view Ok -CPU frequency status view CPU Frequency View Status da frequência do CPU -OK Status view OK -Set state Status view Definir estado -Defaults Pref Window Padrões -Install replicant into Deskbar CPU Frequency View Instalar o replicante na Mesa de Trabalho -Quit Status view Sair -High performance Status view Alto desempenho -Stepping policy CPU Frequency View Política de stepping -Dynamic performance Status view Desempenho dinâmico -Step up by CPU usage Color Step View Aumentar desempenho por uso de CPU -Dynamic stepping CPU Frequency View Stepping dinâmico -Stepping policy: CPU Frequency View Política de stepping: -Integration time [ms]: CPU Frequency View Tempo de integração [ms]: -Open Speedstep preferences… Status view Preferências de Open Speedstep… -Revert Pref Window Reverter -Low energy Status view Baixa energia -Launching the CPU frequency preflet failed.\n\nError: Status view Não foi possível abrir a Frequência de CPU.\n\nErro: -CPUFrequency\n\twritten by Clemens Zeidler\n\tCopyright 2009, Haiku, Inc.\n Status view A Frequência do CPU\n\tfoi escrito por Clemens Zeidler\n\tCopyright 2009, Haiku, Inc.\n -CPUFrequency System name Frequência do CPU diff --git a/data/catalogs/preferences/cpufrequency/pt_br.catkeys b/data/catalogs/preferences/cpufrequency/pt_br.catkeys deleted file mode 100644 index e8d674debe..0000000000 --- a/data/catalogs/preferences/cpufrequency/pt_br.catkeys +++ /dev/null @@ -1,8 +0,0 @@ -1 brazilian_portuguese x-vnd.Haiku-CPUFrequencyPref 1149286520 -CPU frequency status view CPU Frequency View Status da frequência do CPU -CPUFrequency\n\twritten by Clemens Zeidler\n\tCopyright 2009, Haiku, Inc.\n Status view A Frequência do CPU\n\tfoi escrito por Clemens Zeidler\n\tCopyright 2009, Haiku, Inc.\n -Defaults Pref Window Padrões -Install replicant into Deskbar CPU Frequency View Instalar o replicante na Mesa de Trabalho -Launching the CPU frequency preflet failed.\n\nError: Status view Não foi possível abrir a Frequência de CPU.\n\nErro: -Low energy Status view Baixa energia -Set state Status view Definir estado diff --git a/data/catalogs/preferences/cpufrequency/ro.catkeys b/data/catalogs/preferences/cpufrequency/ro.catkeys deleted file mode 100644 index 38acfb5c61..0000000000 --- a/data/catalogs/preferences/cpufrequency/ro.catkeys +++ /dev/null @@ -1,20 +0,0 @@ -1 romanian x-vnd.Haiku-CPUFrequencyPref 3079996868 -Ok Status view Ok -CPU frequency status view CPU Frequency View Vizualizare a stării frecvenței CPU -Set state Status view Stabilește stare -Defaults Pref Window Implicite -Install replicant into Deskbar CPU Frequency View Instalează copie pe Deskbar -Quit Status view Părăsește -High performance Status view Performanță înaltă -Stepping policy CPU Frequency View Regulă de accelerare -Dynamic performance Status view Performanță dinamică -Step up by CPU usage Color Step View Accelerare după utilizarea CPU -Dynamic stepping CPU Frequency View Accelerare dinamică -Stepping policy: CPU Frequency View Regulă de accelerare: -Integration time [ms]: CPU Frequency View Timp de integrare [ms]: -Open Speedstep preferences… Status view Deschide preferințe viteză… -Revert Pref Window Revenire -Low energy Status view Energie scăzută -Launching the CPU frequency preflet failed.\n\nError: Status view Pornirea prefletului frecvență CPU a eșuat.\n\nEroare: -CPUFrequency\n\twritten by Clemens Zeidler\n\tCopyright 2009, Haiku, Inc.\n Status view FrecvențăCPU\n\tscris de Clemens Zeidler\n\tDrept de autor 2009, Haiku, Inc.\n -CPUFrequency System name FrecvențăCPU diff --git a/data/catalogs/preferences/cpufrequency/ru.catkeys b/data/catalogs/preferences/cpufrequency/ru.catkeys deleted file mode 100644 index 850cc69d7d..0000000000 --- a/data/catalogs/preferences/cpufrequency/ru.catkeys +++ /dev/null @@ -1,21 +0,0 @@ -1 russian x-vnd.Haiku-CPUFrequencyPref 1007318924 -Ok Status view ОК -CPU frequency status view CPU Frequency View Просмотр состояния частоты ЦП -OK Status view OK -Set state Status view Выбрать состояние -Defaults Pref Window По умолчанию -Install replicant into Deskbar CPU Frequency View Установить репликант в Deskbar -Quit Status view Выход -High performance Status view Высокая производительность -Stepping policy CPU Frequency View Настройка шага изменения частоты ЦП -Dynamic performance Status view Динамическая производительность -Step up by CPU usage Color Step View Шаг вверх по производительности ЦП: -Dynamic stepping CPU Frequency View Динамическое изменение -Stepping policy: CPU Frequency View Настройка шага изменения частоты ЦП: -Integration time [ms]: CPU Frequency View Время интеграции [мс]: -Open Speedstep preferences… Status view Настроить частоту процессора… -Revert Pref Window Вернуть -Low energy Status view Экономия энергии -Launching the CPU frequency preflet failed.\n\nError: Status view Не удалось запустить настройки частоты ЦП.\n\nОшибка: -CPUFrequency\n\twritten by Clemens Zeidler\n\tCopyright 2009, Haiku, Inc.\n Status view CPUFrequency\n\tразработал Clemens Zeidler\n\tCopyright 2009, Haiku, Inc.\n -CPUFrequency System name Частота процессора diff --git a/data/catalogs/preferences/cpufrequency/sk.catkeys b/data/catalogs/preferences/cpufrequency/sk.catkeys deleted file mode 100644 index 87f5b3572d..0000000000 --- a/data/catalogs/preferences/cpufrequency/sk.catkeys +++ /dev/null @@ -1,21 +0,0 @@ -1 slovak x-vnd.Haiku-CPUFrequencyPref 1007318924 -Ok Status view OK -CPU frequency status view CPU Frequency View Zobrazenie stavy frekvencie CPU -OK Status view OK -Set state Status view Nastaviť stav -Defaults Pref Window Predvoľby -Install replicant into Deskbar CPU Frequency View Nainštalovať replikant do Panelu -Quit Status view Ukončiť -High performance Status view Vysoký výkon -Stepping policy CPU Frequency View Politika krokovania -Dynamic performance Status view Dynamický výkon -Step up by CPU usage Color Step View Krokovať podľa využitia CPU -Dynamic stepping CPU Frequency View Dynamické krokovanie -Stepping policy: CPU Frequency View Politika krokovania: -Integration time [ms]: CPU Frequency View Čas integrácie [ms]: -Open Speedstep preferences… Status view Otvoriť nastavenia Speedstep… -Revert Pref Window Vrátiť -Low energy Status view Nízky odber -Launching the CPU frequency preflet failed.\n\nError: Status view Spustenie konfiguračného apletu Frekvencia CPU zlyhalo.\n\nChyba: -CPUFrequency\n\twritten by Clemens Zeidler\n\tCopyright 2009, Haiku, Inc.\n Status view CPUFrequency\n\tnapísal Clemens Zeidler\n\tCopyright 2009, Haiku, Inc.\n -CPUFrequency System name Frekvencia CPU diff --git a/data/catalogs/preferences/cpufrequency/sv.catkeys b/data/catalogs/preferences/cpufrequency/sv.catkeys deleted file mode 100644 index 8762227b89..0000000000 --- a/data/catalogs/preferences/cpufrequency/sv.catkeys +++ /dev/null @@ -1,21 +0,0 @@ -1 swedish x-vnd.Haiku-CPUFrequencyPref 1007318924 -Ok Status view OK -CPU frequency status view CPU Frequency View Statusvy för ProcessorFrekvens -OK Status view OK -Set state Status view Ändra läge -Defaults Pref Window Förval -Install replicant into Deskbar CPU Frequency View Installera replikant i Deskbar -Quit Status view Avsluta -High performance Status view Hög prestanda -Stepping policy CPU Frequency View Accelerationspolicy -Dynamic performance Status view Dynamisk prestanda -Step up by CPU usage Color Step View Öka vid CPU-belastning -Dynamic stepping CPU Frequency View Dynamisk acceleration -Stepping policy: CPU Frequency View Accelerationspolicy: -Integration time [ms]: CPU Frequency View Integreringstid -Open Speedstep preferences… Status view Öppna inställningar för ProcessorFrekvens… -Revert Pref Window Återgå -Low energy Status view Lågenergiläge -Launching the CPU frequency preflet failed.\n\nError: Status view Misslyckades med att starta inställningsprogrammet ProcessorFrekvens.\n\nFel: -CPUFrequency\n\twritten by Clemens Zeidler\n\tCopyright 2009, Haiku, Inc.\n Status view ProcessorFrekvens\n\tskriven av Clemens Zeidler\n\tCopyright 2009, Haiku, Inc.\n -CPUFrequency System name ProcessorFrekvens diff --git a/data/catalogs/preferences/cpufrequency/uk.catkeys b/data/catalogs/preferences/cpufrequency/uk.catkeys deleted file mode 100644 index 58dd878c6b..0000000000 --- a/data/catalogs/preferences/cpufrequency/uk.catkeys +++ /dev/null @@ -1,20 +0,0 @@ -1 ukrainian x-vnd.Haiku-CPUFrequencyPref 3079996868 -Ok Status view Гаразд -CPU frequency status view CPU Frequency View Статистика частоти ЦП -Set state Status view Встановити стан -Defaults Pref Window По замовчуванню -Install replicant into Deskbar CPU Frequency View Встановити реплікант в Deskbar -Quit Status view Вийти -High performance Status view Висока продуктивність -Stepping policy CPU Frequency View Настройка кроку зміни частоти ЦП -Dynamic performance Status view Динамічна продуктивність -Step up by CPU usage Color Step View Крок вгору по продуктивності ЦП: -Dynamic stepping CPU Frequency View Динамічна зміна -Stepping policy: CPU Frequency View Настройка кроку зміни частоти ЦП: -Integration time [ms]: CPU Frequency View Час інтеграції [мс]: -Open Speedstep preferences… Status view Відкриття покрокової настройки -Revert Pref Window Повернути -Low energy Status view Мале споживання -Launching the CPU frequency preflet failed.\n\nError: Status view Програму Частота процесора не вдалося запустити.\n\nПомилка: -CPUFrequency\n\twritten by Clemens Zeidler\n\tCopyright 2009, Haiku, Inc.\n Status view Частота процесора\n\Автор Клеменс Зейдлер\n\tCopyright 2009, Haiku, Inc.\n -CPUFrequency System name Частота процесора diff --git a/data/catalogs/preferences/cpufrequency/zh-Hans.catkeys b/data/catalogs/preferences/cpufrequency/zh-Hans.catkeys deleted file mode 100644 index 215219bf72..0000000000 --- a/data/catalogs/preferences/cpufrequency/zh-Hans.catkeys +++ /dev/null @@ -1,20 +0,0 @@ -1 english x-vnd.Haiku-CPUFrequencyPref 3079996868 -Ok Status view 确定 -CPU frequency status view CPU Frequency View CPU 状态视图 -Set state Status view 状态设置 -Defaults Pref Window 默认 -Install replicant into Deskbar CPU Frequency View 添加 CPU 监视器到桌面栏 -Quit Status view 退出 -High performance Status view 高性能 -Stepping policy CPU Frequency View 步进策略 -Dynamic performance Status view 动态性能 -Step up by CPU usage Color Step View CPU 步进设置 -Dynamic stepping CPU Frequency View 动态步进 -Stepping policy: CPU Frequency View 步进策略: -Integration time [ms]: CPU Frequency View 采样时间 [ms]: -Open Speedstep preferences… Status view 打开省电设置… -Revert Pref Window 取消 -Low energy Status view 低能耗 -Launching the CPU frequency preflet failed.\n\nError: Status view 启动 CPU 状态通知失败。\n\n错误信息: -CPUFrequency\n\twritten by Clemens Zeidler\n\tCopyright 2009, Haiku, Inc.\n Status view CPU 监视器\n\t编写者:Clemens Zeidler\n\tCopyright 2009,Haiku .Inc。\n -CPUFrequency System name CPU 监视器 diff --git a/data/catalogs/preferences/cpufrequency/zh_Hans.catkeys b/data/catalogs/preferences/cpufrequency/zh_Hans.catkeys deleted file mode 100644 index c93c63c420..0000000000 --- a/data/catalogs/preferences/cpufrequency/zh_Hans.catkeys +++ /dev/null @@ -1,21 +0,0 @@ -1 english x-vnd.Haiku-CPUFrequencyPref 1007318924 -Ok Status view 确定 -CPU frequency status view CPU Frequency View CPU 状态视图 -OK Status view 确定 -Set state Status view 状态设置 -Defaults Pref Window 默认 -Install replicant into Deskbar CPU Frequency View 添加 CPU 监视器到桌面栏 -Quit Status view 退出 -High performance Status view 高性能 -Stepping policy CPU Frequency View 步进策略 -Dynamic performance Status view 动态性能 -Step up by CPU usage Color Step View CPU 步进设置 -Dynamic stepping CPU Frequency View 动态步进 -Stepping policy: CPU Frequency View 步进策略: -Integration time [ms]: CPU Frequency View 采样时间 [ms]: -Open Speedstep preferences… Status view 打开省电设置… -Revert Pref Window 取消 -Low energy Status view 低能耗 -Launching the CPU frequency preflet failed.\n\nError: Status view 启动 CPU 状态通知失败。\n\n错误信息: -CPUFrequency\n\twritten by Clemens Zeidler\n\tCopyright 2009, Haiku, Inc.\n Status view CPU 监视器\n\t编写者:Clemens Zeidler\n\tCopyright 2009,Haiku .Inc。\n -CPUFrequency System name CPU 监视器 diff --git a/docs/user/support/SupportDefs.dox b/docs/user/support/SupportDefs.dox index 8c29d42a89..962a9ccfc6 100644 --- a/docs/user/support/SupportDefs.dox +++ b/docs/user/support/SupportDefs.dox @@ -627,15 +627,13 @@ //! @{ -/*! \fn int32 atomic_set(vint32 *value, int32 newValue) +/*! \fn void atomic_set(int32* value, int32 newValue) \brief Atomically set the variable \a value to \a newvalue. This is a thread-safe way of performing the \c *value \c = \c newValue operation. You should use these function when two or more threads might access the variable simultaneously. You don't have to use a semaphore or a - mutex in this case. - - \return The original value of \c value. + mutex in this case. The variable must be naturally aligned. \sa atomic_set64() for a version that works on \c long \c long. \sa atomic_test_and_set() @@ -646,7 +644,28 @@ */ -/*! \fn int32 atomic_test_and_set(vint32 *value, int32 newValue, +/*! \fn int32 atomic_get_and_set(int32* value, int32 newValue) + \brief Atomically set the variable \a value to \a newvalue and return the + old value. + + This is a thread-safe way of performing the \c *value \c = \c newValue + operation. You should use these function when two or more threads might + access the variable simultaneously. You don't have to use a semaphore or a + mutex in this case. + + \return The original value of \c value. + + \sa atomic_get_and_set64() for a version that works on \c long \c long. + \sa atomic_set() + \sa atomic_test_and_set() + \sa atomic_add() + \sa atomic_and() + \sa atomic_or(), + \sa atomic_get() +*/ + + +/*! \fn int32 atomic_test_and_set(int32* value, int32 newValue, int32 testAgainst) \brief Atomically set the variable \a value to \a newValue if the current value is \a testAgainst. @@ -659,6 +678,7 @@ \return The original value of \c value. \sa atomic_test_and_set64() for a version that works on \c long \c long. + \sa atomic_get_and_set() \sa atomic_set() \sa atomic_add() \sa atomic_and() @@ -668,7 +688,7 @@ /*! - \fn int32 atomic_add(vint32 *value, int32 addValue) + \fn int32 atomic_add(int32* value, int32 addValue) \brief Atomically add the value of \a addValue to \a value. This is a thread-safe way of performing the \c *value \c += \c addValue @@ -679,6 +699,7 @@ \return The original value of \c value. \sa atomic_add64() for a version that works on \c long \c long. + \sa atomic_get_and_set() \sa atomic_set() \sa atomic_test_and_set() \sa atomic_and() @@ -687,7 +708,7 @@ */ -/*! \fn int32 atomic_and(vint32 *value, int32 andValue) +/*! \fn int32 atomic_and(int32* value, int32 andValue) \brief Atomically perform a bitwise AND operation of \a andValue to the variable \a andValue. @@ -699,6 +720,7 @@ \return The original value of \c value. \sa atomic_and64() for a version that works on \c long \c long. + \sa atomic_get_and_set() \sa atomic_set() \sa atomic_test_and_set() \sa atomic_add() @@ -709,7 +731,7 @@ /*! - \fn int32 atomic_or(vint32 *value, int32 orValue) + \fn int32 atomic_or(int32* value, int32 orValue) \brief Atomically perform a bitwise OR operation of \a orValue to the variable \a andValue. @@ -721,6 +743,7 @@ \return The original value of \c value. \sa atomic_or64() for a version that works on \c long \c long. + \sa atomic_get_and_set() \sa atomic_set() \sa atomic_test_and_set() \sa atomic_add() @@ -730,17 +753,18 @@ /*! - \fn int32 atomic_get(vint32 *value) + \fn int32 atomic_get(int32* value) \brief Atomically return the value of \c value. This is a thread-safe way of reading the contents of the \c value operation. You should use these function when two or more threads might access the variable simultaneously. You don't have to use a semaphore or a - mutex in this case. + mutex in this case. The variable must be naturally aligned. \return The original value of \c value. \sa atomic_get64() for a version that works on \c long \c long. + \sa atomic_get_and_set() \sa atomic_set() \sa atomic_test_and_set() \sa atomic_add() @@ -750,17 +774,16 @@ /*! - \fn int64 atomic_set64(vint64 *value, int64 newValue) + \fn void atomic_set64(int64* value, int64 newValue) \brief Atomically set the variable \a value to \a newvalue. This is a thread-safe way of performing the \c *value \c = \c newValue operation. You should use these function when two or more threads might access the variable simultaneously. You don't have to use a semaphore or a - mutex in this case. - - \return The original value of \c value. + mutex in this case. The variable must be naturally aligned. \sa atomic_set() for a version that works on an \c int32. + \sa atomic_get_and_set64() \sa atomic_test_and_set64() \sa atomic_add64() \sa atomic_and64() @@ -770,7 +793,29 @@ /*! - \fn int64 atomic_test_and_set64(vint64 *value, int64 newValue, + \fn int64 atomic_get_and_set64(int64* value, int64 newValue) + \brief Atomically set the variable \a value to \a newvalue and return + the old value. + + This is a thread-safe way of performing the \c *value \c = \c newValue + operation. You should use these function when two or more threads might + access the variable simultaneously. You don't have to use a semaphore or a + mutex in this case. + + \return The original value of \c value. + + \sa atomic_get_and_set() for a version that works on an \c int32. + \sa atomic_set64() + \sa atomic_test_and_set64() + \sa atomic_add64() + \sa atomic_and64() + \sa atomic_or64() + \sa atomic_get64() +*/ + + +/*! + \fn int64 atomic_test_and_set64(int64* value, int64 newValue, int64 testAgainst) \brief Atomically set the variable \a value to \a newValue if the current value is \a testAgainst. @@ -783,6 +828,7 @@ \return The original value of \c value. \sa atomic_test_and_set() for a version that works on an \c int32. + \sa atomic_get_and_set64() \sa atomic_set64() \sa atomic_add64() \sa atomic_and64() @@ -792,7 +838,7 @@ /*! - \fn int64 atomic_add64(vint64 *value, int64 addValue) + \fn int64 atomic_add64(int64* value, int64 addValue) \brief Atomically add the value of \a addValue to \a value. This is a thread-safe way of performing the \c *value \c += \c addValue @@ -803,6 +849,7 @@ \return The original value of \c value. \sa atomic_add() for a version that works on an \c int32. + \sa atomic_get_and_set64() \sa atomic_set64() \sa atomic_test_and_set64() \sa atomic_and64() @@ -812,7 +859,7 @@ /*! - \fn int64 atomic_and64(vint64 *value, int64 andValue) + \fn int64 atomic_and64(int64* value, int64 andValue) \brief Atomically perform a bitwise AND operation of \a andValue to the variable \a andValue. @@ -824,6 +871,7 @@ \return The original value of \c value. \sa atomic_and() for a version that works on an \c int32. + \sa atomic_get_and_set64() \sa atomic_set64() \sa atomic_test_and_set64() \sa atomic_add64() @@ -832,7 +880,7 @@ */ -/*! \fn int64 atomic_or64(vint64 *value, int64 orValue) +/*! \fn int64 atomic_or64(int64* value, int64 orValue) \brief Atomically perform a bitwise OR operation of \a orValue to the variable \a andValue. @@ -844,6 +892,7 @@ \return The original value of \c value. \sa atomic_or() for a version that works on an \c int32. + \sa atomic_get_and_set64() \sa atomic_set64() \sa atomic_test_and_set64() \sa atomic_add64() @@ -853,17 +902,18 @@ /*! - \fn int64 atomic_get64(vint64 *value) + \fn int64 atomic_get64(int64* value) \brief Atomically return the value of \c value. This is a thread-safe way of reading the contents of the \c value operation. You should use these function when two or more threads might access the variable simultaneously. You don't have to use a semaphore or a - mutex in this case. + mutex in this case. The variable must be naturally aligned. \return The original value of \c value. \sa atomic_get() for a version that works on an \c int32. + \sa atomic_get_and_set64() \sa atomic_set64() \sa atomic_test_and_set64() \sa atomic_add64() diff --git a/headers/build/HaikuBuildCompatibility.h b/headers/build/HaikuBuildCompatibility.h index 009c77f1d5..38b5197fb8 100644 --- a/headers/build/HaikuBuildCompatibility.h +++ b/headers/build/HaikuBuildCompatibility.h @@ -118,17 +118,19 @@ struct media_node; extern "C" { #endif -extern int32 atomic_set(vint32 *value, int32 newValue); -extern int32 atomic_test_and_set(vint32 *value, int32 newValue, +extern void atomic_set(int32* value, int32 newValue); +extern int32 atomic_get_and_set(int32* value, int32 newValue); +extern int32 atomic_test_and_set(int32 *value, int32 newValue, int32 testAgainst); -extern int32 atomic_get(vint32 *value); -extern int64 atomic_set64(vint64 *value, int64 newValue); -extern int64 atomic_test_and_set64(vint64 *value, int64 newValue, +extern int32 atomic_get(int32 *value); +extern void atomic_set64(int64* value, int64 newValue); +extern int64 atomic_get_and_set64(int64* value, int64 newValue); +extern int64 atomic_test_and_set64(int64 *value, int64 newValue, int64 testAgainst); -extern int64 atomic_get64(vint64 *value); -extern int64 atomic_add64(vint64 *value, int64 addValue); -extern int64 atomic_and64(vint64 *value, int64 andValue); -extern int64 atomic_or64(vint64 *value, int64 orValue); +extern int64 atomic_get64(int64 *value); +extern int64 atomic_add64(int64 *value, int64 addValue); +extern int64 atomic_and64(int64 *value, int64 andValue); +extern int64 atomic_or64(int64 *value, int64 orValue); extern size_t strnlen(const char *string, size_t count); diff --git a/headers/cpp/std/bastring.h b/headers/cpp/std/bastring.h index 774f7be3e9..15bf4b5c86 100644 --- a/headers/cpp/std/bastring.h +++ b/headers/cpp/std/bastring.h @@ -66,7 +66,7 @@ extern void __length_error (const char *); #endif #ifdef __HAIKU__ -extern "C" __haiku_int32 atomic_add(volatile __haiku_int32* value, +extern "C" __haiku_int32 atomic_add(__haiku_int32* value, __haiku_int32 addvalue); #endif /* __HAIKU__ */ @@ -82,7 +82,7 @@ private: charT* data () { return reinterpret_cast(this + 1); } charT& operator[] (size_t s) { return data () [s]; } #ifdef __HAIKU__ - charT* grab () { if (selfish) return clone (); atomic_add((volatile __haiku_int32*) &ref, 1); return data (); } + charT* grab () { if (selfish) return clone (); atomic_add((__haiku_int32*) &ref, 1); return data (); } void release() { if (atomic_add((__haiku_int32*) &ref, -1) == 1) delete this; } #else charT* grab () { if (selfish) return clone (); ++ref; return data (); } diff --git a/headers/os/drivers/KernelExport.h b/headers/os/drivers/KernelExport.h index 98e59387f1..ffdbb245ea 100644 --- a/headers/os/drivers/KernelExport.h +++ b/headers/os/drivers/KernelExport.h @@ -20,9 +20,9 @@ typedef ulong cpu_status; #if B_DEBUG_SPINLOCK_CONTENTION typedef struct { - vint32 lock; - vint32 count_low; - vint32 count_high; + int32 lock; + int32 count_low; + int32 count_high; } spinlock; # define B_SPINLOCK_INITIALIZER { 0, 0, 0 } @@ -31,15 +31,39 @@ typedef ulong cpu_status; (spinlock)->count_low = 0; \ (spinlock)->count_high = 0; \ } while (false) -# define B_SPINLOCK_IS_LOCKED(spinlock) ((spinlock)->lock > 0) #else - typedef vint32 spinlock; + typedef struct { + int32 lock; + } spinlock; -# define B_SPINLOCK_INITIALIZER 0 -# define B_INITIALIZE_SPINLOCK(lock) do { *(lock) = 0; } while (false) -# define B_SPINLOCK_IS_LOCKED(lock) (*(lock) > 0) +# define B_SPINLOCK_INITIALIZER { 0 } +# define B_INITIALIZE_SPINLOCK(spinlock) do { \ + (spinlock)->lock = 0; \ + } while (false) #endif +#define B_SPINLOCK_IS_LOCKED(spinlock) (atomic_get(&(spinlock)->lock) > 0) + +typedef struct { + int32 lock; +} rw_spinlock; + +#define B_RW_SPINLOCK_INITIALIZER { 0 } +#define B_INITIALIZE_RW_SPINLOCK(rw_spinlock) do { \ + (rw_spinlock)->lock = 0; \ + } while (false) + +typedef struct { + spinlock lock; + uint32 count; +} seqlock; + +#define B_SEQLOCK_INITIALIZER { B_SPINLOCK_INITIALIZER, 0 } +#define B_INITIALIZE_SEQLOCK(seqlock) do { \ + B_INITIALIZE_SPINLOCK(&(seqlock)->lock); \ + (seqlock)->count = 0; \ + } while (false) + /* interrupt handling support for device drivers */ typedef int32 (*interrupt_handler)(void *data); @@ -126,6 +150,19 @@ extern void restore_interrupts(cpu_status status); extern void acquire_spinlock(spinlock *lock); extern void release_spinlock(spinlock *lock); +extern bool try_acquire_write_spinlock(rw_spinlock* lock); +extern void acquire_write_spinlock(rw_spinlock* lock); +extern void release_write_spinlock(rw_spinlock* lock); +extern bool try_acquire_read_spinlock(rw_spinlock* lock); +extern void acquire_read_spinlock(rw_spinlock* lock); +extern void release_read_spinlock(rw_spinlock* lock); + +extern bool try_acquire_write_seqlock(seqlock* lock); +extern void acquire_write_seqlock(seqlock* lock); +extern void release_write_seqlock(seqlock* lock); +extern uint32 acquire_read_seqlock(seqlock* lock); +extern bool release_read_seqlock(seqlock* lock, uint32 count); + extern status_t install_io_interrupt_handler(long interrupt_number, interrupt_handler handler, void *data, ulong flags); extern status_t remove_io_interrupt_handler(long interrupt_number, diff --git a/headers/os/drivers/cpufreq.h b/headers/os/drivers/cpufreq.h new file mode 100644 index 0000000000..3eb04b72b5 --- /dev/null +++ b/headers/os/drivers/cpufreq.h @@ -0,0 +1,32 @@ +/* + * Copyright 2013, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _CPUFREQ_H +#define _CPUFREQ_H + + +#include + +#include + + +#define CPUFREQ_MODULES_PREFIX "power/cpufreq" + + +const int kCPUPerformanceScaleMax = 1000; + +typedef struct cpufreq_module_info { + module_info info; + + float rank; + + void (*cpufreq_set_scheduler_mode)(enum scheduler_mode mode); + + status_t (*cpufreq_increase_performance)(int delta); + status_t (*cpufreq_decrease_performance)(int delta); +} cpufreq_module_info; + + +#endif // _CPUFREQ_H + diff --git a/headers/os/drivers/cpuidle.h b/headers/os/drivers/cpuidle.h index 7649cdadab..2373978af9 100644 --- a/headers/os/drivers/cpuidle.h +++ b/headers/os/drivers/cpuidle.h @@ -8,50 +8,22 @@ #include -#ifdef __cplusplus -extern "C" { -#endif - -#define CPUIDLE_CSTATE_MAX 8 -#define CSTATE_NAME_LENGTH 32 -#define B_CPUIDLE_MODULE_NAME "generic/cpuidle/v1" +#include -struct CpuidleStat { - uint64 usageCount; - bigtime_t usageTime; -}; +#define CPUIDLE_MODULES_PREFIX "power/cpuidle" -struct CpuidleInfo { - int32 cstateSleep; - CpuidleStat stats[CPUIDLE_CSTATE_MAX]; -}; +typedef struct cpuidle_module_info { + module_info info; -struct CpuidleDevice; + float rank; -struct CpuidleCstate { - char name[CSTATE_NAME_LENGTH]; - int32 latency; - int32 (*EnterIdle)(int32 state, CpuidleDevice *device); - void *pData; -}; + void (*cpuidle_set_scheduler_mode)(enum scheduler_mode mode); + void (*cpuidle_idle)(void); + void (*cpuidle_wait)(int32* variable, int32 test); +} cpuidle_module_info; -struct CpuidleDevice { - CpuidleCstate cStates[CPUIDLE_CSTATE_MAX]; - int32 cStateCount; -}; - - -struct CpuidleModuleInfo { - module_info info; - status_t (*AddDevice)(CpuidleDevice *device); -}; - - -#ifdef __cplusplus -} -#endif #endif // _CPUIDLE_MODULE_H diff --git a/headers/os/kernel/OS.h b/headers/os/kernel/OS.h index 19d080dc0e..5adb85ce66 100644 --- a/headers/os/kernel/OS.h +++ b/headers/os/kernel/OS.h @@ -420,244 +420,108 @@ extern void ktrace_vprintf(const char *format, va_list args); /* System information */ -#if __INTEL__ -# define B_MAX_CPU_COUNT 8 -#elif __x86_64__ -# define B_MAX_CPU_COUNT 8 -#elif __POWERPC__ -# define B_MAX_CPU_COUNT 8 -#elif __M68K__ -# define B_MAX_CPU_COUNT 1 -#elif __ARM__ || __ARMEL__ || __ARMEB__ -# define B_MAX_CPU_COUNT 1 -#elif __MIPSEL__ -# define B_MAX_CPU_COUNT 1 -#else -# warning Unknown cpu -# define B_MAX_CPU_COUNT 1 -#endif +typedef struct { + bigtime_t active_time; /* usec of doing useful work since boot */ + bool enabled; +} cpu_info; -typedef enum cpu_types { - /* TODO: add latest models */ +typedef struct { + bigtime_t boot_time; /* time of boot (usecs since 1/1/1970) */ - /* Motorola/IBM */ - B_CPU_PPC_UNKNOWN = 0, - B_CPU_PPC_601 = 1, - B_CPU_PPC_602 = 7, - B_CPU_PPC_603 = 2, - B_CPU_PPC_603e = 3, - B_CPU_PPC_603ev = 8, - B_CPU_PPC_604 = 4, - B_CPU_PPC_604e = 5, - B_CPU_PPC_604ev = 9, - B_CPU_PPC_620 = 10, - B_CPU_PPC_750 = 6, - B_CPU_PPC_686 = 13, - B_CPU_PPC_860 = 25, - B_CPU_PPC_7400 = 26, - B_CPU_PPC_7410 = 27, - B_CPU_PPC_7447A = 28, - B_CPU_PPC_7448 = 29, - B_CPU_PPC_7450 = 30, - B_CPU_PPC_7455 = 31, - B_CPU_PPC_7457 = 32, - B_CPU_PPC_8240 = 33, - B_CPU_PPC_8245 = 34, + uint32 cpu_count; /* number of cpus */ - B_CPU_PPC_IBM_401A1 = 35, - B_CPU_PPC_IBM_401B2 = 36, - B_CPU_PPC_IBM_401C2 = 37, - B_CPU_PPC_IBM_401D2 = 38, - B_CPU_PPC_IBM_401E2 = 39, - B_CPU_PPC_IBM_401F2 = 40, - B_CPU_PPC_IBM_401G2 = 41, - B_CPU_PPC_IBM_403 = 42, - B_CPU_PPC_IBM_405GP = 43, - B_CPU_PPC_IBM_405L = 44, - B_CPU_PPC_IBM_750FX = 45, - B_CPU_PPC_IBM_POWER3 = 46, + uint64 max_pages; /* total # of accessible pages */ + uint64 used_pages; /* # of accessible pages in use */ + uint64 cached_pages; + uint64 block_cache_pages; + uint64 ignored_pages; /* # of ignored/inaccessible pages */ - /* Intel */ + uint64 needed_memory; + uint64 free_memory; - /* Updated according to Intel(R) Processor Identification and - * the CPUID instruction (Table 4) - * AP-485 Intel - 24161832.pdf - */ - B_CPU_INTEL_x86 = 0x1000, - B_CPU_INTEL_PENTIUM = 0x1051, - B_CPU_INTEL_PENTIUM75, - B_CPU_INTEL_PENTIUM_486_OVERDRIVE, - B_CPU_INTEL_PENTIUM_MMX, - B_CPU_INTEL_PENTIUM_MMX_MODEL_4 = B_CPU_INTEL_PENTIUM_MMX, - B_CPU_INTEL_PENTIUM_MMX_MODEL_8 = 0x1058, - B_CPU_INTEL_PENTIUM75_486_OVERDRIVE, - B_CPU_INTEL_PENTIUM_PRO = 0x1061, - B_CPU_INTEL_PENTIUM_II = 0x1063, - B_CPU_INTEL_PENTIUM_II_MODEL_3 = 0x1063, - B_CPU_INTEL_PENTIUM_II_MODEL_5 = 0x1065, - B_CPU_INTEL_CELERON = 0x1066, - B_CPU_INTEL_CELERON_MODEL_22 = 0x11066, - B_CPU_INTEL_PENTIUM_III = 0x1067, - B_CPU_INTEL_PENTIUM_III_MODEL_8 = 0x1068, - B_CPU_INTEL_PENTIUM_M = 0x1069, - B_CPU_INTEL_PENTIUM_III_XEON = 0x106a, - B_CPU_INTEL_PENTIUM_III_MODEL_11 = 0x106b, - B_CPU_INTEL_ATOM = 0x1106c, - B_CPU_INTEL_PENTIUM_M_MODEL_13 = 0x106d, /* Dothan */ - B_CPU_INTEL_PENTIUM_CORE, - B_CPU_INTEL_PENTIUM_CORE_2, - B_CPU_INTEL_PENTIUM_CORE_2_45_NM = 0x11067, /* Core 2 on 45 nm - (Core 2 Extreme, - Xeon model 23 or - Core 2 Duo/Quad) */ - B_CPU_INTEL_PENTIUM_CORE_I5_M430 = 0x21065, /* Core i5 M 430 @ 2.27 */ - B_CPU_INTEL_PENTIUM_CORE_I7 = 0x1106a, /* Core i7 920 @ 2.6(6) */ - B_CPU_INTEL_PENTIUM_CORE_I7_Q720 = 0x1106e, /* Core i7 Q720 @ 1.6 */ - B_CPU_INTEL_PENTIUM_IV = 0x10f0, - B_CPU_INTEL_PENTIUM_IV_MODEL_1, - B_CPU_INTEL_PENTIUM_IV_MODEL_2, - B_CPU_INTEL_PENTIUM_IV_MODEL_3, - B_CPU_INTEL_PENTIUM_IV_MODEL_4, + uint64 max_swap_pages; + uint64 free_swap_pages; - /* AMD */ + uint32 page_faults; /* # of page faults */ - // AMD Processor Recognition Application Note - B_CPU_AMD_x86 = 0x1100, + uint32 max_sems; + uint32 used_sems; - // Family 5h - B_CPU_AMD_K5_MODEL_0 = 0x1150, - B_CPU_AMD_K5_MODEL_1 = 0x1151, - B_CPU_AMD_K5_MODEL_2 = 0x1152, - B_CPU_AMD_K5_MODEL_3 = 0x1153, - B_CPU_AMD_K6_MODEL_6 = 0x1156, - B_CPU_AMD_K6_MODEL_7 = 0x1157, - B_CPU_AMD_K6_MODEL_8 = 0x1158, - B_CPU_AMD_K6_2 = 0x1158, - B_CPU_AMD_K6_MODEL_9 = 0x1159, - B_CPU_AMD_K6_III = 0x1159, - B_CPU_AMD_K6_III_MODEL_13 = 0x115d, + uint32 max_ports; + uint32 used_ports; - B_CPU_AMD_GEODE_LX = 0x115a, + uint32 max_threads; + uint32 used_threads; - // Family 6h - B_CPU_AMD_ATHLON_MODEL_1 = 0x1161, - B_CPU_AMD_ATHLON_MODEL_2 = 0x1162, + uint32 max_teams; + uint32 used_teams; - B_CPU_AMD_DURON = 0x1163, + char kernel_name[B_FILE_NAME_LENGTH]; + char kernel_build_date[B_OS_NAME_LENGTH]; + char kernel_build_time[B_OS_NAME_LENGTH]; - B_CPU_AMD_ATHLON_THUNDERBIRD = 0x1164, - B_CPU_AMD_ATHLON_XP_MODEL_6 = 0x1166, - B_CPU_AMD_ATHLON_XP_MODEL_7 = 0x1167, - B_CPU_AMD_ATHLON_XP_MODEL_8 = 0x1168, - B_CPU_AMD_ATHLON_XP_MODEL_10 = 0x116a, /* Barton */ + int64 kernel_version; + uint32 abi; /* the system API */ +} system_info; - // Family fh - B_CPU_AMD_ATHLON_64_MODEL_3 = 0x11f3, - B_CPU_AMD_ATHLON_64_MODEL_4 = 0x11f4, - B_CPU_AMD_ATHLON_64_MODEL_7 = 0x11f7, - B_CPU_AMD_ATHLON_64_MODEL_8 = 0x11f8, - B_CPU_AMD_ATHLON_64_MODEL_11 = 0x11fb, - B_CPU_AMD_ATHLON_64_MODEL_12 = 0x11fc, - B_CPU_AMD_ATHLON_64_MODEL_14 = 0x11fe, - B_CPU_AMD_ATHLON_64_MODEL_15 = 0x11ff, - B_CPU_AMD_ATHLON_64_MODEL_20 = 0x111f4, - B_CPU_AMD_ATHLON_64_MODEL_23 = 0x111f7, - B_CPU_AMD_ATHLON_64_MODEL_24 = 0x111f8, - B_CPU_AMD_ATHLON_64_MODEL_27 = 0x111fb, +enum topology_level_type { + B_TOPOLOGY_UNKNOWN, + B_TOPOLOGY_ROOT, + B_TOPOLOGY_SMT, + B_TOPOLOGY_CORE, + B_TOPOLOGY_PACKAGE +}; - // Athlon 64's below here could be really - // Sempron 64's... however i've yet to find - // proof online - B_CPU_AMD_ATHLON_64_MODEL_31 = 0x111ff, - B_CPU_AMD_ATHLON_64_MODEL_35 = 0x211f3, - B_CPU_AMD_ATHLON_64_MODEL_43 = 0x211fb, - B_CPU_AMD_ATHLON_64_MODEL_47 = 0x211ff, - B_CPU_AMD_ATHLON_64_MODEL_63 = 0x311ff, - B_CPU_AMD_ATHLON_64_MODEL_79 = 0x411ff, - B_CPU_AMD_ATHLON_64_MODEL_95 = 0x511ff, - - B_CPU_AMD_SEMPRON_64_MODEL_28 = 0x111fc, - B_CPU_AMD_SEMPRON_64_MODEL_44 = 0x211fc, - B_CPU_AMD_SEMPRON_64_MODEL_127 = 0x711ff, - - B_CPU_AMD_OPTERON_MODEL_5 = 0x11f5, - B_CPU_AMD_OPTERON_MODEL_21 = 0x111f5, - B_CPU_AMD_OPTERON_MODEL_33 = 0x211f1, - B_CPU_AMD_OPTERON_MODEL_37 = 0x211f5, - B_CPU_AMD_OPTERON_MODEL_39 = 0x211f7, - - B_CPU_AMD_TURION_64_MODEL_36 = 0x211f4, - B_CPU_AMD_TURION_64_MODEL_76 = 0x411fc, - B_CPU_AMD_TURION_64_MODEL_104 = 0x611f8, - - // Family 10h - B_CPU_AMD_PHENOM_MODEL_2 = 0x1011f2, - B_CPU_AMD_PHENOM_II_MODEL_4 = 0x1011f4, - B_CPU_AMD_PHENOM_II_MODEL_5 = 0x1011f5, - B_CPU_AMD_PHENOM_II_MODEL_6 = 0x1011f6, - B_CPU_AMD_PHENOM_II_MODEL_10 = 0x1011fa, - - // Family 12h - B_CPU_AMD_A_SERIES_MODEL_1 = 0x3011f1, - B_CPU_AMD_A_SERIES_MODEL_16 = 0x6111f0, - B_CPU_AMD_A_SERIES_MODEL_19 = 0x6111f3, - - // Family 14h - B_CPU_AMD_C_SERIES = 0x5011f1, - B_CPU_AMD_E_SERIES = 0x5011f2, - - // Family 15h - B_CPU_AMD_FX_SERIES_MODEL_1 = 0x6011f1, /* Bulldozer */ - B_CPU_AMD_FX_SERIES_MODEL_2 = 0x6011f2, - - /* VIA/Cyrix */ - B_CPU_CYRIX_x86 = 0x1200, - B_CPU_VIA_CYRIX_x86 = 0x1200, - B_CPU_CYRIX_GXm = 0x1254, - B_CPU_CYRIX_6x86MX = 0x1260, - - /* VIA/IDT */ - B_CPU_IDT_x86 = 0x1300, - B_CPU_VIA_IDT_x86 = 0x1300, - B_CPU_IDT_WINCHIP_C6 = 0x1354, - B_CPU_IDT_WINCHIP_2 = 0x1358, - B_CPU_IDT_WINCHIP_3, - B_CPU_VIA_C3_SAMUEL = 0x1366, - B_CPU_VIA_C3_SAMUEL_2 = 0x1367, - B_CPU_VIA_C3_EZRA_T = 0x1368, - B_CPU_VIA_C3_NEHEMIAH = 0x1369, - B_CPU_VIA_C7_ESTHER = 0x136a, - B_CPU_VIA_C7_ESTHER_2 = 0x136d, - B_CPU_VIA_NANO_ISAIAH = 0x136f, - - /* Transmeta */ - B_CPU_TRANSMETA_x86 = 0x1600, - B_CPU_TRANSMETA_CRUSOE = 0x1654, - B_CPU_TRANSMETA_EFFICEON = 0x16f2, - B_CPU_TRANSMETA_EFFICEON_2 = 0x16f3, - - /* Rise */ - B_CPU_RISE_x86 = 0x1400, - B_CPU_RISE_mP6 = 0x1450, - - /* National Semiconductor */ - B_CPU_NATIONAL_x86 = 0x1500, - B_CPU_NATIONAL_GEODE_GX1 = 0x1554, - B_CPU_NATIONAL_GEODE_GX2, - - /* For compatibility */ - B_CPU_AMD_29K = 14, +enum cpu_platform { + B_CPU_UNKNOWN, B_CPU_x86, - B_CPU_MC6502, - B_CPU_Z80, - B_CPU_ALPHA, - B_CPU_MIPS, - B_CPU_HPPA, - B_CPU_M68K, - B_CPU_ARM, - B_CPU_SH, - B_CPU_SPARC -} cpu_type; + B_CPU_x86_64 +}; + +enum cpu_vendor { + B_CPU_VENDOR_UNKNOWN, + B_CPU_VENDOR_AMD, + B_CPU_VENDOR_CYRIX, + B_CPU_VENDOR_IDT, + B_CPU_VENDOR_INTEL, + B_CPU_VENDOR_NATIONAL_SEMICONDUCTOR, + B_CPU_VENDOR_RISE, + B_CPU_VENDOR_TRANSMETA, + B_CPU_VENDOR_VIA +}; + +typedef struct { + enum cpu_platform platform; +} cpu_topology_root_info; + +typedef struct { + enum cpu_vendor vendor; + uint32 cache_line_size; +} cpu_topology_package_info; + +typedef struct { + uint32 model; + uint64 default_frequency; +} cpu_topology_core_info; + +typedef struct { + uint32 id; + enum topology_level_type type; + uint32 level; + + union { + cpu_topology_root_info root; + cpu_topology_package_info package; + cpu_topology_core_info core; + } data; +} cpu_topology_node_info; + + +extern status_t get_system_info(system_info* info); +extern status_t get_cpu_info(uint32 firstCPU, uint32 cpuCount, + cpu_info* info); +extern status_t get_cpu_topology_info(cpu_topology_node_info* topologyInfos, + uint32* topologyInfoCount); #define B_CPU_x86_VENDOR_MASK 0xff00 @@ -713,76 +577,6 @@ extern status_t get_cpuid(cpuid_info *info, uint32 eaxRegister, #endif -typedef enum platform_types { - B_BEBOX_PLATFORM = 0, - B_MAC_PLATFORM, - B_AT_CLONE_PLATFORM, - B_ENIAC_PLATFORM, - B_APPLE_II_PLATFORM, - B_CRAY_PLATFORM, - B_LISA_PLATFORM, - B_TI_994A_PLATFORM, - B_TIMEX_SINCLAIR_PLATFORM, - B_ORAC_1_PLATFORM, - B_HAL_PLATFORM, - B_BESM_6_PLATFORM, - B_MK_61_PLATFORM, - B_NINTENDO_64_PLATFORM, - B_AMIGA_PLATFORM, - B_ATARI_PLATFORM, - B_64_BIT_PC_PLATFORM -} platform_type; - -typedef struct { - bigtime_t active_time; /* usec of doing useful work since boot */ -} cpu_info; - - -typedef int32 machine_id[2]; /* unique machine ID */ - -typedef struct { - machine_id id; /* unique machine ID */ - bigtime_t boot_time; /* time of boot (usecs since 1/1/1970) */ - - int32 cpu_count; /* number of cpus */ - enum cpu_types cpu_type; /* type of cpu */ - int32 cpu_revision; /* revision # of cpu */ - cpu_info cpu_infos[B_MAX_CPU_COUNT]; /* info about individual cpus */ - int64 cpu_clock_speed; /* processor clock speed (Hz) */ - int64 bus_clock_speed; /* bus clock speed (Hz) */ - enum platform_types platform_type; /* type of machine we're on */ - - int32 max_pages; /* total # of accessible pages */ - int32 used_pages; /* # of accessible pages in use */ - int32 page_faults; /* # of page faults */ - int32 max_sems; - int32 used_sems; - int32 max_ports; - int32 used_ports; - int32 max_threads; - int32 used_threads; - int32 max_teams; - int32 used_teams; - - char kernel_name[B_FILE_NAME_LENGTH]; - char kernel_build_date[B_OS_NAME_LENGTH]; - char kernel_build_time[B_OS_NAME_LENGTH]; - int64 kernel_version; - - bigtime_t _busy_wait_time; /* reserved for whatever */ - - int32 cached_pages; - uint32 abi; /* the system API */ - int32 ignored_pages; /* # of ignored/inaccessible pages */ - int32 pad; -} system_info; - -/* system private, use macro instead */ -extern status_t _get_system_info(system_info *info, size_t size); - -#define get_system_info(info) \ - _get_system_info((info), sizeof(*(info))) - extern int32 is_computer_on(void); extern double is_computer_on_fire(void); diff --git a/headers/os/kernel/scheduler.h b/headers/os/kernel/scheduler.h index f55eb2ff57..be3508775e 100644 --- a/headers/os/kernel/scheduler.h +++ b/headers/os/kernel/scheduler.h @@ -49,6 +49,11 @@ enum be_task_flags { B_MIDI_PROCESSING = 0x800 }; +enum scheduler_mode { + SCHEDULER_MODE_LOW_LATENCY, + SCHEDULER_MODE_POWER_SAVING, +}; + #if defined(__cplusplus) extern "C" { @@ -58,6 +63,9 @@ int32 suggest_thread_priority(uint32 task_flags = B_DEFAULT_MEDIA_PRIORITY, bigtime_t estimate_max_scheduling_latency(thread_id th = -1); /* default is current thread */ +status_t set_scheduler_mode(int32 mode); +int32 get_scheduler_mode(void); + } #else @@ -67,6 +75,9 @@ int32 suggest_thread_priority(uint32 what, int32 period, bigtime_t jitter, bigtime_t estimate_max_scheduling_latency(thread_id th); /* default is current thread */ +status_t set_scheduler_mode(int32 mode); +int32 get_scheduler_mode(void); + #endif #endif // SCHEDULER_H diff --git a/headers/os/media/TimeSource.h b/headers/os/media/TimeSource.h index cd8a783dfb..7a76e54b26 100644 --- a/headers/os/media/TimeSource.h +++ b/headers/os/media/TimeSource.h @@ -113,7 +113,7 @@ private: private: bool fStarted; area_id fArea; - volatile BPrivate::media::TimeSourceTransmit* fBuf; + BPrivate::media::TimeSourceTransmit* fBuf; BPrivate::media::SlaveNodes* fSlaveNodes; area_id _reserved_area; diff --git a/headers/os/support/String.h b/headers/os/support/String.h index e33fbc0540..7ca3b64442 100644 --- a/headers/os/support/String.h +++ b/headers/os/support/String.h @@ -396,8 +396,8 @@ private: int32 withLength); private: - vint32& _ReferenceCount(); - const vint32& _ReferenceCount() const; + int32& _ReferenceCount(); + const int32& _ReferenceCount() const; bool _IsShareable() const; void _FreePrivateData(); diff --git a/headers/os/support/SupportDefs.h b/headers/os/support/SupportDefs.h index 7cc5aaf67e..aae8002000 100644 --- a/headers/os/support/SupportDefs.h +++ b/headers/os/support/SupportDefs.h @@ -196,19 +196,21 @@ extern "C" { #endif /* Atomic functions; previous value is returned */ -extern int32 atomic_set(vint32 *value, int32 newValue); -extern int32 atomic_test_and_set(vint32 *value, int32 newValue, int32 testAgainst); -extern int32 atomic_add(vint32 *value, int32 addValue); -extern int32 atomic_and(vint32 *value, int32 andValue); -extern int32 atomic_or(vint32 *value, int32 orValue); -extern int32 atomic_get(vint32 *value); +extern void atomic_set(int32* value, int32 newValue); +extern int32 atomic_get_and_set(int32* value, int32 newValue); +extern int32 atomic_test_and_set(int32 *value, int32 newValue, int32 testAgainst); +extern int32 atomic_add(int32 *value, int32 addValue); +extern int32 atomic_and(int32 *value, int32 andValue); +extern int32 atomic_or(int32 *value, int32 orValue); +extern int32 atomic_get(int32 *value); -extern int64 atomic_set64(vint64 *value, int64 newValue); -extern int64 atomic_test_and_set64(vint64 *value, int64 newValue, int64 testAgainst); -extern int64 atomic_add64(vint64 *value, int64 addValue); -extern int64 atomic_and64(vint64 *value, int64 andValue); -extern int64 atomic_or64(vint64 *value, int64 orValue); -extern int64 atomic_get64(vint64 *value); +extern void atomic_set64(int64* value, int64 newValue); +extern int64 atomic_get_and_set64(int64* value, int64 newValue); +extern int64 atomic_test_and_set64(int64 *value, int64 newValue, int64 testAgainst); +extern int64 atomic_add64(int64 *value, int64 addValue); +extern int64 atomic_and64(int64 *value, int64 andValue); +extern int64 atomic_or64(int64 *value, int64 orValue); +extern int64 atomic_get64(int64 *value); /* Other stuff */ extern void* get_stack_frame(void); @@ -240,15 +242,6 @@ extern void* get_stack_frame(void); __sync_fetch_and_and(valuePointer, andValue) #define atomic_or(valuePointer, orValue) \ __sync_fetch_and_or(valuePointer, orValue) -#define atomic_get(valuePointer) \ - __sync_fetch_and_or(valuePointer, 0) - // No equivalent to atomic_get(). We simulate it via atomic or. On most - // (all?) 32+ bit architectures aligned 32 bit reads will be atomic anyway, - // though. - -// Note: No equivalent for atomic_set(). It could be simulated by a -// get + atomic test and set loop, but calling the atomic_set() implementation -// might be faster. #endif // B_USE_BUILTIN_ATOMIC_FUNCTIONS && __GNUC__ >= 4 diff --git a/headers/posix/unistd.h b/headers/posix/unistd.h index dc5897efd0..92fa579fe6 100644 --- a/headers/posix/unistd.h +++ b/headers/posix/unistd.h @@ -104,10 +104,8 @@ /* TODO: check */ #define _SC_IOV_MAX 32 #define _SC_UIO_MAXIOV _SC_IOV_MAX -#define _SC_NPROCESSORS_MAX 33 #define _SC_NPROCESSORS_CONF 34 #define _SC_NPROCESSORS_ONLN 35 -#define _SC_CPUID_MAX 36 #define _SC_ATEXIT_MAX 37 #define _SC_PASS_MAX 39 #define _SC_PHYS_PAGES 40 diff --git a/headers/private/device/power_managment.h b/headers/private/device/power_managment.h index 1fad929c98..7964a27240 100644 --- a/headers/private/device/power_managment.h +++ b/headers/private/device/power_managment.h @@ -14,19 +14,6 @@ enum { // ioctl response with kMagicFreqID IDENTIFY_DEVICE = B_DEVICE_OP_CODES_END + 20001, - // CPU Frequence: - // get a list of freq_info, the list is terminated with a element with - // frequency = 0 - GET_CPU_FREQ_STATES = B_DEVICE_OP_CODES_END + 20005, - // get and set a freq_info - GET_CURENT_CPU_FREQ_STATE, - SET_CPU_FREQ_STATE, - // start watching for frequency changes, ioctl blocks until the frequency - // has changed - WATCH_CPU_FREQ, - // stop all watching ioctl, ioctl return B_ERROR - STOP_WATCHING_CPU_FREQ, - GET_BATTERY_INFO, GET_EXTENDED_BATTERY_INFO, WATCH_BATTERY, @@ -34,22 +21,6 @@ enum { }; -// CPU Frequence: -// magic id returned by IDENTIFY_DEVICE -const uint32 kMagicFreqID = 48921; - - -#define MAX_CPU_FREQUENCY_STATES 10 - - -typedef struct { - uint16 frequency; // [Mhz] - uint16 volts; - uint16 id; - int power; -} freq_info; - - // ACPI Battery: // magic id returned by IDENTIFY_DEVICE const uint32 kMagicACPIBatteryID = 17822; diff --git a/headers/private/firewire/fwglue.h b/headers/private/firewire/fwglue.h index 896224093f..453ad32465 100644 --- a/headers/private/firewire/fwglue.h +++ b/headers/private/firewire/fwglue.h @@ -30,7 +30,7 @@ typedef uint32_t bus_addr_t; typedef uint32_t bus_size_t; -#define atomic_readandclear_int(ptr) atomic_set((int32 *)(ptr), 0) +#define atomic_readandclear_int(ptr) atomic_get_and_set((int32*)(ptr), 0) #define atomic_set_int(ptr, value) atomic_or((int32 *)(ptr), value) #define mtx_lock mutex_lock diff --git a/headers/private/fs_shell/fssh_api_wrapper.h b/headers/private/fs_shell/fssh_api_wrapper.h index b0d9a3dcd4..46bd50939f 100644 --- a/headers/private/fs_shell/fssh_api_wrapper.h +++ b/headers/private/fs_shell/fssh_api_wrapper.h @@ -50,6 +50,7 @@ // #pragma mark - fssh_atomic.h #define atomic_set fssh_atomic_set +#define atomic_get_and_Set fssh_atomic_get_and_set #define atomic_test_and_set fssh_atomic_test_and_set #define atomic_add fssh_atomic_add #define atomic_and fssh_atomic_and diff --git a/headers/private/fs_shell/fssh_atomic.h b/headers/private/fs_shell/fssh_atomic.h index df307a46f1..90fba9ca7f 100644 --- a/headers/private/fs_shell/fssh_atomic.h +++ b/headers/private/fs_shell/fssh_atomic.h @@ -15,21 +15,23 @@ extern "C" { #endif -int32_t fssh_atomic_set(vint32_t *value, int32_t newValue); -int32_t fssh_atomic_test_and_set(vint32_t *value, int32_t newValue, +void fssh_atomic_set(int32_t* value, int32_t newValue); +int32_t fssh_atomic_get_and_set(int32_t* value, int32_t newValue); +int32_t fssh_atomic_test_and_set(int32_t *value, int32_t newValue, int32_t testAgainst); -int32_t fssh_atomic_add(vint32_t *value, int32_t addValue); -int32_t fssh_atomic_and(vint32_t *value, int32_t andValue); -int32_t fssh_atomic_or(vint32_t *value, int32_t orValue); -int32_t fssh_atomic_get(vint32_t *value); +int32_t fssh_atomic_add(int32_t *value, int32_t addValue); +int32_t fssh_atomic_and(int32_t *value, int32_t andValue); +int32_t fssh_atomic_or(int32_t *value, int32_t orValue); +int32_t fssh_atomic_get(int32_t *value); -int64_t fssh_atomic_set64(vint64_t *value, int64_t newValue); -int64_t fssh_atomic_test_and_set64(vint64_t *value, int64_t newValue, +void fssh_atomic_set64(int64_t* value, int64_t newValue); +int64_t fssh_atomic_get_and_set64(int64_t* value, int64_t newValue); +int64_t fssh_atomic_test_and_set64(int64_t *value, int64_t newValue, int64_t testAgainst); -int64_t fssh_atomic_add64(vint64_t *value, int64_t addValue); -int64_t fssh_atomic_and64(vint64_t *value, int64_t andValue); -int64_t fssh_atomic_or64(vint64_t *value, int64_t orValue); -int64_t fssh_atomic_get64(vint64_t *value); +int64_t fssh_atomic_add64(int64_t *value, int64_t addValue); +int64_t fssh_atomic_and64(int64_t *value, int64_t andValue); +int64_t fssh_atomic_or64(int64_t *value, int64_t orValue); +int64_t fssh_atomic_get64(int64_t *value); #ifdef __cplusplus } diff --git a/headers/private/graphics/intel_extreme/lock.h b/headers/private/graphics/intel_extreme/lock.h index 9c0f8423fa..255e177f94 100644 --- a/headers/private/graphics/intel_extreme/lock.h +++ b/headers/private/graphics/intel_extreme/lock.h @@ -14,7 +14,7 @@ typedef struct lock { sem_id sem; - vint32 count; + int32 count; } lock; diff --git a/headers/private/graphics/radeon_hd/lock.h b/headers/private/graphics/radeon_hd/lock.h index e76c4e4f45..9557bc98b5 100644 --- a/headers/private/graphics/radeon_hd/lock.h +++ b/headers/private/graphics/radeon_hd/lock.h @@ -14,7 +14,7 @@ typedef struct lock { sem_id sem; - vint32 count; + int32 count; } lock; @@ -82,4 +82,4 @@ class Autolock { }; -#endif /* LOCK_H */ \ No newline at end of file +#endif /* LOCK_H */ diff --git a/headers/private/kernel/DPC.h b/headers/private/kernel/DPC.h index 9267910822..3c883a7a21 100644 --- a/headers/private/kernel/DPC.h +++ b/headers/private/kernel/DPC.h @@ -62,10 +62,8 @@ public: uint32 reservedSlots); void Close(bool cancelPending); - status_t Add(DPCCallback* callback, - bool schedulerLocked); - status_t Add(void (*function)(void*), void* argument, - bool schedulerLocked); + status_t Add(DPCCallback* callback); + status_t Add(void (*function)(void*), void* argument); bool Cancel(DPCCallback* callback); thread_id Thread() const diff --git a/headers/private/kernel/MessagingServiceDefs.h b/headers/private/kernel/MessagingServiceDefs.h index 81a353c0ed..9d1c40aede 100644 --- a/headers/private/kernel/MessagingServiceDefs.h +++ b/headers/private/kernel/MessagingServiceDefs.h @@ -17,7 +17,7 @@ enum { }; struct messaging_area_header { - vint32 lock_counter; + int32 lock_counter; int32 size; // set to 0, when area is discarded area_id kernel_area; area_id next_kernel_area; diff --git a/headers/private/kernel/UserEvent.h b/headers/private/kernel/UserEvent.h index 1b8ceb70b2..34086bc57e 100644 --- a/headers/private/kernel/UserEvent.h +++ b/headers/private/kernel/UserEvent.h @@ -92,7 +92,7 @@ private: private: ThreadCreationAttributes fCreationAttributes; char fThreadName[B_OS_NAME_LENGTH]; - bool fPendingDPC; + int32 fPendingDPC; }; diff --git a/headers/private/kernel/UserTimer.h b/headers/private/kernel/UserTimer.h index 2f439c1b88..026aa55575 100644 --- a/headers/private/kernel/UserTimer.h +++ b/headers/private/kernel/UserTimer.h @@ -54,6 +54,8 @@ protected: inline void UpdatePeriodicStartTime(); inline void CheckPeriodicOverrun(bigtime_t now); + inline void CancelTimer(); + protected: int32 fID; timer fTimer; @@ -62,6 +64,7 @@ protected: bigtime_t fInterval; uint32 fOverrunCount; bool fScheduled; // fTimer scheduled + int32 fSkip; }; diff --git a/headers/private/kernel/arch/atomic.h b/headers/private/kernel/arch/atomic.h new file mode 100644 index 0000000000..c958b3c6d6 --- /dev/null +++ b/headers/private/kernel/arch/atomic.h @@ -0,0 +1,22 @@ +/* + * Copyright 2014, Paweł Dziepak, pdziepak@quarnos.org. + * Distributed under the terms of the MIT License. + */ +#ifndef _KERNEL_ARCH_ATOMIC_H +#define _KERNEL_ARCH_ATOMIC_H + + +#include + +#include + + +#ifdef __x86_64__ +# include +#elif __INTEL__ +# include +#endif + + +#endif // _KERNEL_ARCH_ATOMIC_H + diff --git a/headers/private/kernel/arch/cpu.h b/headers/private/kernel/arch/cpu.h index e1bf1fdb5e..188df59081 100644 --- a/headers/private/kernel/arch/cpu.h +++ b/headers/private/kernel/arch/cpu.h @@ -41,13 +41,8 @@ ssize_t arch_cpu_user_strlcpy(char *to, const char *from, size_t size, status_t arch_cpu_user_memset(void *s, char c, size_t count, addr_t *faultHandler); -void arch_cpu_idle(void); void arch_cpu_sync_icache(void *address, size_t length); -void arch_cpu_memory_read_barrier(void); -void arch_cpu_memory_write_barrier(void); -void arch_cpu_memory_read_write_barrier(void); - #ifdef __cplusplus } @@ -55,4 +50,6 @@ void arch_cpu_memory_read_write_barrier(void); #include +#define CACHE_LINE_ALIGN __attribute__((aligned(CACHE_LINE_SIZE))) + #endif /* _KERNEL_ARCH_CPU_H */ diff --git a/headers/private/kernel/arch/int.h b/headers/private/kernel/arch/int.h index 9ebe6b0717..6d4afc6f67 100644 --- a/headers/private/kernel/arch/int.h +++ b/headers/private/kernel/arch/int.h @@ -34,6 +34,7 @@ void arch_int_enable_io_interrupt(int irq); void arch_int_disable_io_interrupt(int irq); void arch_int_configure_io_interrupt(int irq, uint32 config); bool arch_int_are_interrupts_enabled(void); +void arch_int_assign_to_cpu(int32 irq, int32 cpu); #ifdef __cplusplus } diff --git a/headers/private/kernel/arch/smp.h b/headers/private/kernel/arch/smp.h index e8a66b97da..4b59e45041 100644 --- a/headers/private/kernel/arch/smp.h +++ b/headers/private/kernel/arch/smp.h @@ -8,23 +8,18 @@ #include + struct kernel_args; +class CPUSet; -// must match MAX_BOOT_CPUS in platform_kernel_args.h -#define SMP_MAX_CPUS MAX_BOOT_CPUS -#ifdef __cplusplus -extern "C" { -#endif +status_t arch_smp_init(kernel_args* args); +status_t arch_smp_per_cpu_init(kernel_args* args, int32 cpu); -status_t arch_smp_init(struct kernel_args *args); -status_t arch_smp_per_cpu_init(struct kernel_args *args, int32 cpu); void arch_smp_send_ici(int32 target_cpu); -void arch_smp_send_broadcast_ici(void); +void arch_smp_send_broadcast_ici(); +void arch_smp_send_multicast_ici(CPUSet& cpuSet); -#ifdef __cplusplus -} -#endif #endif /* KERNEL_ARCH_SMP_H */ diff --git a/headers/private/kernel/arch/system_info.h b/headers/private/kernel/arch/system_info.h index 3a5fb24c8e..f765be64bd 100644 --- a/headers/private/kernel/arch/system_info.h +++ b/headers/private/kernel/arch/system_info.h @@ -18,7 +18,7 @@ extern "C" { #endif status_t arch_system_info_init(struct kernel_args *args); -status_t arch_get_system_info(system_info *info, size_t size); +void arch_fill_topology_node(cpu_topology_node_info* node, int32 cpu); #ifdef __cplusplus } diff --git a/headers/private/kernel/arch/x86/32/atomic.h b/headers/private/kernel/arch/x86/32/atomic.h new file mode 100644 index 0000000000..adec9c05c3 --- /dev/null +++ b/headers/private/kernel/arch/x86/32/atomic.h @@ -0,0 +1,97 @@ +/* + * Copyright 2014, Paweł Dziepak, pdziepak@quarnos.org. + * Distributed under the terms of the MIT License. + */ +#ifndef _KERNEL_ARCH_X86_32_ATOMIC_H +#define _KERNEL_ARCH_X86_32_ATOMIC_H + + +static inline void +memory_read_barrier_inline(void) +{ + asm volatile("lock; addl $0, (%%esp)" : : : "memory"); +} + + +static inline void +memory_write_barrier_inline(void) +{ + asm volatile("lock; addl $0, (%%esp)" : : : "memory"); +} + + +static inline void +memory_full_barrier_inline(void) +{ + asm volatile("lock; addl $0, (%%esp)" : : : "memory"); +} + + +#define memory_read_barrier memory_read_barrier_inline +#define memory_write_barrier memory_write_barrier_inline +#define memory_full_barrier memory_full_barrier_inline + + +static inline void +atomic_set_inline(int32* value, int32 newValue) +{ + memory_write_barrier(); + *(volatile int32*)value = newValue; +} + + +static inline int32 +atomic_get_and_set_inline(int32* value, int32 newValue) +{ + asm volatile("xchgl %0, (%1)" + : "+r" (newValue) + : "r" (value) + : "memory"); + return newValue; +} + + +static inline int32 +atomic_test_and_set_inline(int32* value, int32 newValue, int32 testAgainst) +{ + asm volatile("lock; cmpxchgl %2, (%3)" + : "=a" (newValue) + : "0" (testAgainst), "r" (newValue), "r" (value) + : "memory"); + return newValue; +} + + +static inline int32 +atomic_add_inline(int32* value, int32 newValue) +{ + asm volatile("lock; xaddl %0, (%1)" + : "+r" (newValue) + : "r" (value) + : "memory"); + return newValue; +} + + +static inline int32 +atomic_get_inline(int32* value) +{ + int32 newValue = *(volatile int32*)value; + memory_read_barrier(); + return newValue; +} + + +#define atomic_set atomic_set_inline +#define atomic_get_and_set atomic_get_and_set_inline +#ifndef atomic_test_and_set +# define atomic_test_and_set atomic_test_and_set_inline +#endif +#ifndef atomic_add +# define atomic_add atomic_add_inline +#endif +#define atomic_get atomic_get_inline + + +#endif // _KERNEL_ARCH_X86_32_ATOMIC_H + diff --git a/headers/private/kernel/arch/x86/32/descriptors.h b/headers/private/kernel/arch/x86/32/descriptors.h index e09b849e3a..5308ce0547 100644 --- a/headers/private/kernel/arch/x86/32/descriptors.h +++ b/headers/private/kernel/arch/x86/32/descriptors.h @@ -9,30 +9,42 @@ #define _KERNEL_ARCH_X86_32_DESCRIPTORS_H -#define KERNEL_CODE_SEG 0x8 -#define KERNEL_DATA_SEG 0x10 +// Segments common for all CPUs. +#define KERNEL_CODE_SEGMENT 1 +#define KERNEL_DATA_SEGMENT 2 -#define USER_CODE_SEG 0x1b -#define USER_DATA_SEG 0x23 +#define USER_CODE_SEGMENT 3 +#define USER_DATA_SEGMENT 4 -#define APM_CODE32_SEGMENT 0x28 -#define APM_CODE16_SEGMENT 0x30 -#define APM_DATA_SEGMENT 0x38 +#define APM_CODE32_SEGMENT 5 +#define APM_CODE16_SEGMENT 6 +#define APM_DATA_SEGMENT 7 -#define BIOS_DATA_SEGMENT 0x40 +#define BIOS_DATA_SEGMENT 8 + +// Per-CPU segments. +#define TSS_SEGMENT 9 +#define DOUBLE_FAULT_TSS_SEGMENT 10 +#define KERNEL_TLS_SEGMENT 11 +#define USER_TLS_SEGMENT 12 +#define APM_SEGMENT 13 + +#define GDT_SEGMENT_COUNT 14 + + +#define KERNEL_CODE_SELECTOR ((KERNEL_CODE_SEGMENT << 3) | DPL_KERNEL) +#define KERNEL_DATA_SELECTOR ((KERNEL_DATA_SEGMENT << 3) | DPL_KERNEL) + +#define USER_CODE_SELECTOR ((USER_CODE_SEGMENT << 3) | DPL_USER) +#define USER_DATA_SELECTOR ((USER_DATA_SEGMENT << 3) | DPL_USER) + +#define KERNEL_TLS_SELECTOR ((KERNEL_TLS_SEGMENT << 3) | DPL_KERNEL) #ifndef _ASSEMBLER // this file can also be included from assembler as well // (and is in arch_interrupts.S) -#define DOUBLE_FAULT_TSS_BASE_SEGMENT 9 -#define TSS_BASE_SEGMENT (DOUBLE_FAULT_TSS_BASE_SEGMENT + smp_get_num_cpus()) -#define TLS_BASE_SEGMENT (TSS_BASE_SEGMENT + smp_get_num_cpus()) -#define APM_BASE_SEGMENT (TLS_BASE_SEGMENT + smp_get_num_cpus()) - -#define TSS_SEGMENT(cpu) (TSS_BASE_SEGMENT + cpu) - // defines entries in the GDT/LDT struct segment_descriptor { @@ -73,6 +85,9 @@ struct tss { uint16 io_map_base; }; +typedef segment_descriptor global_descriptor_table[GDT_SEGMENT_COUNT]; +extern global_descriptor_table gGDTs[]; + static inline void clear_segment_descriptor(segment_descriptor* desc) @@ -141,6 +156,13 @@ set_tss_descriptor(segment_descriptor* desc, addr_t base, uint32 limit) } +static inline segment_descriptor* +get_gdt(int32 cpu) +{ + return gGDTs[cpu]; +} + + #endif /* _ASSEMBLER */ #endif /* _KERNEL_ARCH_X86_32_DESCRIPTORS_H */ diff --git a/headers/private/kernel/arch/x86/32/iframe.h b/headers/private/kernel/arch/x86/32/iframe.h index 47c423826f..8362b75d83 100644 --- a/headers/private/kernel/arch/x86/32/iframe.h +++ b/headers/private/kernel/arch/x86/32/iframe.h @@ -37,7 +37,7 @@ struct iframe { uint32 user_ss; }; -#define IFRAME_IS_USER(f) ((f)->cs == USER_CODE_SEG \ +#define IFRAME_IS_USER(f) ((f)->cs == USER_CODE_SELECTOR \ || ((f)->flags & 0x20000) != 0) diff --git a/headers/private/kernel/arch/x86/64/atomic.h b/headers/private/kernel/arch/x86/64/atomic.h new file mode 100644 index 0000000000..fd567319f6 --- /dev/null +++ b/headers/private/kernel/arch/x86/64/atomic.h @@ -0,0 +1,153 @@ +/* + * Copyright 2014, Paweł Dziepak, pdziepak@quarnos.org. + * Distributed under the terms of the MIT License. + */ +#ifndef _KERNEL_ARCH_X86_64_ATOMIC_H +#define _KERNEL_ARCH_X86_64_ATOMIC_H + + +static inline void +memory_read_barrier_inline(void) +{ + asm volatile("lfence" : : : "memory"); +} + + +static inline void +memory_write_barrier_inline(void) +{ + asm volatile("sfence" : : : "memory"); +} + + +static inline void +memory_full_barrier_inline(void) +{ + asm volatile("mfence" : : : "memory"); +} + + +#define memory_read_barrier memory_read_barrier_inline +#define memory_write_barrier memory_write_barrier_inline +#define memory_full_barrier memory_full_barrier_inline + + +static inline void +atomic_set_inline(int32* value, int32 newValue) +{ + memory_write_barrier(); + *(volatile int32*)value = newValue; +} + + +static inline int32 +atomic_get_and_set_inline(int32* value, int32 newValue) +{ + asm volatile("xchg %0, (%1)" + : "+r" (newValue) + : "r" (value) + : "memory"); + return newValue; +} + + +static inline int32 +atomic_test_and_set_inline(int32* value, int32 newValue, int32 testAgainst) +{ + asm volatile("lock; cmpxchgl %2, (%3)" + : "=a" (newValue) + : "0" (testAgainst), "r" (newValue), "r" (value) + : "memory"); + return newValue; +} + + +static inline int32 +atomic_add_inline(int32* value, int32 newValue) +{ + asm volatile("lock; xaddl %0, (%1)" + : "+r" (newValue) + : "r" (value) + : "memory"); + return newValue; +} + + +static inline int32 +atomic_get_inline(int32* value) +{ + int32 newValue = *(volatile int32*)value; + memory_read_barrier(); + return newValue; +} + + +static inline void +atomic_set64_inline(int64* value, int64 newValue) +{ + memory_write_barrier(); + *(volatile int64*)value = newValue; +} + + +static inline int64 +atomic_get_and_set64_inline(int64* value, int64 newValue) +{ + asm volatile("xchgq %0, (%1)" + : "+r" (newValue) + : "r" (value) + : "memory"); + return newValue; +} + + +static inline int64 +atomic_test_and_set64_inline(int64* value, int64 newValue, int64 testAgainst) +{ + asm volatile("lock; cmpxchgq %2, (%3)" + : "=a" (newValue) + : "0" (testAgainst), "r" (newValue), "r" (value) + : "memory"); + return newValue; +} + + +static inline int64 +atomic_add64_inline(int64* value, int64 newValue) +{ + asm volatile("lock; xaddq %0, (%1)" + : "+r" (newValue) + : "r" (value) + : "memory"); + return newValue; +} + + +static inline int64 +atomic_get64_inline(int64* value) +{ + int64 newValue = *(volatile int64*)value; + memory_read_barrier(); + return newValue; +} + + +#define atomic_set atomic_set_inline +#define atomic_get_and_set atomic_get_and_set_inline +#ifndef atomic_test_and_set +# define atomic_test_and_set atomic_test_and_set_inline +#endif +#ifndef atomic_add +# define atomic_add atomic_add_inline +#endif +#define atomic_get atomic_get_inline + +#define atomic_set64 atomic_set64_inline +#define atomic_get_and_set64 atomic_get_and_set64_inline +#define atomic_test_and_set64 atomic_test_and_set64_inline +#define atomic_add64 atomic_add64_inline +#define atomic_get64 atomic_get64_inline + + +#endif // _KERNEL_ARCH_X86_64_ATOMIC_H + diff --git a/headers/private/kernel/arch/x86/64/descriptors.h b/headers/private/kernel/arch/x86/64/descriptors.h index 3f05196586..fc9e5d0177 100644 --- a/headers/private/kernel/arch/x86/64/descriptors.h +++ b/headers/private/kernel/arch/x86/64/descriptors.h @@ -8,19 +8,28 @@ // Segment definitions. // Note that the ordering of these is important to SYSCALL/SYSRET. -#define KERNEL_CODE_SEG 0x08 -#define KERNEL_DATA_SEG 0x10 -#define USER_DATA_SEG 0x1b -#define USER_CODE_SEG 0x23 +#define KERNEL_CODE_SEGMENT 1 +#define KERNEL_DATA_SEGMENT 2 +#define USER_DATA_SEGMENT 3 +#define USER_CODE_SEGMENT 4 + +#define TSS_BASE_SEGMENT 5 + +#define TSS_SEGMENT(cpu) (TSS_BASE_SEGMENT + cpu * 2) + +#define GDT_SEGMENT_COUNT (TSS_BASE_SEGMENT + SMP_MAX_CPUS * 2) + + +#define KERNEL_CODE_SELECTOR ((KERNEL_CODE_SEGMENT << 3) | DPL_KERNEL) +#define KERNEL_DATA_SELECTOR ((KERNEL_DATA_SEGMENT << 3) | DPL_KERNEL) + +#define USER_CODE_SELECTOR ((USER_CODE_SEGMENT << 3) | DPL_USER) +#define USER_DATA_SELECTOR ((USER_DATA_SEGMENT << 3) | DPL_USER) #ifndef _ASSEMBLER -#define TSS_BASE_SEGMENT 5 -#define TSS_SEGMENT(cpu) (TSS_BASE_SEGMENT + cpu * 2) - - // Structure of a segment descriptor. struct segment_descriptor { uint32 limit0 : 16; diff --git a/headers/private/kernel/arch/x86/apic.h b/headers/private/kernel/arch/x86/apic.h index 9c3d92284a..a9dbed7852 100644 --- a/headers/private/kernel/arch/x86/apic.h +++ b/headers/private/kernel/arch/x86/apic.h @@ -52,7 +52,7 @@ #define APIC_TRIGGER_MODE_LEVEL (1 << 15) /* Interrupt Command defines */ -#define APIC_INTR_COMMAND_1_MASK 0xfff3f000 +#define APIC_INTR_COMMAND_1_MASK 0xfff32000 #define APIC_INTR_COMMAND_2_MASK 0x00ffffff #define APIC_INTR_COMMAND_1_DEST_MODE_PHYSICAL 0 @@ -110,6 +110,7 @@ #if !_BOOT_MODE bool apic_available(); +bool x2apic_available(); uint32 apic_read(uint32 offset); void apic_write(uint32 offset, uint32 data); uint32 apic_local_id(); @@ -122,10 +123,9 @@ void apic_disable_local_ints(); uint32 apic_spurious_intr_vector(); void apic_set_spurious_intr_vector(uint32 config); -uint32 apic_intr_command_1(); -void apic_set_intr_command_1(uint32 config); -uint32 apic_intr_command_2(); -void apic_set_intr_command_2(uint32 config); + +void apic_set_interrupt_command(uint32 destination, uint32 mode); +bool apic_interrupt_delivered(void); uint32 apic_lvt_timer(); void apic_set_lvt_timer(uint32 config); diff --git a/headers/private/kernel/arch/x86/arch_cpu.h b/headers/private/kernel/arch/x86/arch_cpu.h index 4809528c57..f745c50c6d 100644 --- a/headers/private/kernel/arch/x86/arch_cpu.h +++ b/headers/private/kernel/arch/x86/arch_cpu.h @@ -24,14 +24,25 @@ #endif // !_ASSEMBLER +#define CPU_MAX_CACHE_LEVEL 8 + +#define CACHE_LINE_SIZE 64 + + // MSR registers (possibly Intel specific) #define IA32_MSR_TSC 0x10 #define IA32_MSR_APIC_BASE 0x1b +#define IA32_MSR_PLATFORM_INFO 0xce +#define IA32_MSR_MPERF 0xe7 +#define IA32_MSR_APERF 0xe8 #define IA32_MSR_MTRR_CAPABILITIES 0xfe #define IA32_MSR_SYSENTER_CS 0x174 #define IA32_MSR_SYSENTER_ESP 0x175 #define IA32_MSR_SYSENTER_EIP 0x176 +#define IA32_MSR_PERF_STATUS 0x198 +#define IA32_MSR_PERF_CTL 0x199 +#define IA32_MSR_TURBO_RATIO_LIMIT 0x1ad #define IA32_MSR_ENERGY_PERF_BIAS 0x1b0 #define IA32_MSR_MTRR_DEFAULT_TYPE 0x2ff #define IA32_MSR_MTRR_PHYSICAL_BASE_0 0x200 @@ -152,6 +163,10 @@ #define IA32_FEATURE_EXT_RDRND (1 << 30) // RDRAND instruction #define IA32_FEATURE_EXT_HYPERVISOR (1 << 31) // Running on a hypervisor +// x86 features from cpuid eax 0x80000001, ecx register (AMD) +#define IA32_FEATURE_AMD_EXT_CMPLEGACY (1 << 1) // Core MP legacy mode +#define IA32_FEATURE_AMD_EXT_TOPOLOGY (1 << 22) // Topology extensions + // x86 features from cpuid eax 0x80000001, edx register (AMD) // only care about the ones that are unique to this register #define IA32_FEATURE_AMD_EXT_SYSCALL (1 << 11) // SYSCALL/SYSRET @@ -170,6 +185,10 @@ | IA32_FEATURE_AMD_EXT_RDTSCP \ | IA32_FEATURE_AMD_EXT_LONG) +// x86 defined features from cpuid eax 5, ecx register +#define IA32_FEATURE_POWER_MWAIT (1 << 0) +#define IA32_FEATURE_INTERRUPT_MWAIT (1 << 1) + // x86 defined features from cpuid eax 6, eax register // reference http://www.intel.com/Assets/en_US/PDF/appnote/241618.pdf (Table 5-11) #define IA32_FEATURE_DTS (1 << 0) //Digital Thermal Sensor @@ -184,6 +203,9 @@ #define IA32_FEATURE_APERFMPERF (1 << 0) //IA32_APERF, IA32_MPERF #define IA32_FEATURE_EPB (1 << 3) //IA32_ENERGY_PERF_BIAS +// x86 defined features from cpuid eax 0x80000007, edx register +#define IA32_FEATURE_INVARIANT_TSC (1 << 8) + // cr4 flags #define IA32_CR4_PAE (1UL << 5) #define IA32_CR4_GLOBAL_PAGES (1UL << 7) @@ -265,9 +287,12 @@ typedef struct x86_cpu_module_info { enum x86_feature_type { FEATURE_COMMON = 0, // cpuid eax=1, ecx register FEATURE_EXT, // cpuid eax=1, edx register + FEATURE_EXT_AMD_ECX, // cpuid eax=0x80000001, ecx register (AMD) FEATURE_EXT_AMD, // cpuid eax=0x80000001, edx register (AMD) + FEATURE_5_ECX, // cpuid eax=5, ecx register FEATURE_6_EAX, // cpuid eax=6, eax registers FEATURE_6_ECX, // cpuid eax=6, ecx registers + FEATURE_EXT_7_EDX, // cpuid eax=0x80000007, edx register FEATURE_NUM }; @@ -301,6 +326,8 @@ typedef struct arch_cpu_info { int model; int extended_model; + uint32 logical_apic_id; + struct X86PagingStructures* active_paging_structures; size_t dr6; // temporary storage for debug registers (cf. @@ -310,13 +337,11 @@ typedef struct arch_cpu_info { struct tss tss; #ifndef __x86_64__ struct tss double_fault_tss; + void* kernel_tls; #endif } arch_cpu_info; -#undef PAUSE -#define PAUSE() asm volatile ("pause;") - #define nop() __asm__ ("nop"::) #define x86_read_cr0() ({ \ @@ -410,6 +435,9 @@ typedef struct arch_cpu_info { }) +extern void (*gCpuIdleFunc)(void); + + #ifdef __cplusplus extern "C" { #endif @@ -462,6 +490,20 @@ void x86_fnsave_swap(void* oldFpuState, const void* newFpuState); #endif +static inline void +arch_cpu_idle(void) +{ + gCpuIdleFunc(); +} + + +static inline void +arch_cpu_pause(void) +{ + asm volatile("pause" : : : "memory"); +} + + #ifdef __cplusplus } // extern "C" { #endif diff --git a/headers/private/kernel/arch/x86/arch_int.h b/headers/private/kernel/arch/x86/arch_int.h index da4943726d..bfbe401061 100644 --- a/headers/private/kernel/arch/x86/arch_int.h +++ b/headers/private/kernel/arch/x86/arch_int.h @@ -11,6 +11,13 @@ #define NUM_IO_VECTORS (256 - ARCH_INTERRUPT_BASE) +enum irq_source { + IRQ_SOURCE_INVALID, + IRQ_SOURCE_IOAPIC, + IRQ_SOURCE_MSI, +}; + + static inline void arch_int_enable_interrupts_inline(void) { @@ -68,9 +75,12 @@ typedef struct interrupt_controller_s { bool (*is_spurious_interrupt)(int32 num); bool (*is_level_triggered_interrupt)(int32 num); bool (*end_of_interrupt)(int32 num); + void (*assign_interrupt_to_cpu)(int32 num, int32 cpu); } interrupt_controller; +void x86_set_irq_source(int irq, irq_source source); + void arch_int_set_interrupt_controller(const interrupt_controller &controller); #endif // __cplusplus diff --git a/headers/private/kernel/arch/x86/arch_kernel_args.h b/headers/private/kernel/arch/x86/arch_kernel_args.h index 7e6c967582..a0dbae7bdb 100644 --- a/headers/private/kernel/arch/x86/arch_kernel_args.h +++ b/headers/private/kernel/arch/x86/arch_kernel_args.h @@ -40,8 +40,8 @@ typedef struct { uint32 apic_phys; FixedWidthPointer apic; uint32 ioapic_phys; - uint32 cpu_apic_id[MAX_BOOT_CPUS]; - uint32 cpu_apic_version[MAX_BOOT_CPUS]; + uint32 cpu_apic_id[SMP_MAX_CPUS]; + uint32 cpu_apic_version[SMP_MAX_CPUS]; // hpet stuff uint32 hpet_phys; FixedWidthPointer hpet; diff --git a/headers/private/kernel/arch/x86/arch_smp.h b/headers/private/kernel/arch/x86/arch_smp.h index 5b2d654efc..4eef8eb00f 100644 --- a/headers/private/kernel/arch/x86/arch_smp.h +++ b/headers/private/kernel/arch/x86/arch_smp.h @@ -99,4 +99,18 @@ enum { MP_INTR_TYPE_ExtINT, }; + +#ifdef __cplusplus +extern "C" { +#endif + + +uint32 x86_get_cpu_apic_id(int32 cpu); + + +#ifdef __cplusplus +} +#endif + + #endif /* _KERNEL_ARCH_x86_ARCH_SMP_H */ diff --git a/headers/private/kernel/arch/x86/arch_system_info.h b/headers/private/kernel/arch/x86/arch_system_info.h index b8a7383de9..0f92e3799f 100644 --- a/headers/private/kernel/arch/x86/arch_system_info.h +++ b/headers/private/kernel/arch/x86/arch_system_info.h @@ -12,7 +12,7 @@ extern "C" { #endif -status_t get_current_cpuid(cpuid_info* info, uint32 eax); +status_t get_current_cpuid(cpuid_info* info, uint32 eax, uint32 ecx); uint32 get_eflags(void); void set_eflags(uint32 value); diff --git a/headers/private/kernel/arch/x86/arch_thread.h b/headers/private/kernel/arch/x86/arch_thread.h index 0769195543..3689d0b44b 100644 --- a/headers/private/kernel/arch/x86/arch_thread.h +++ b/headers/private/kernel/arch/x86/arch_thread.h @@ -30,9 +30,6 @@ void x86_restart_syscall(struct iframe* frame); void x86_set_tls_context(Thread* thread); -#ifdef __x86_64__ - - static inline Thread* arch_thread_get_current_thread(void) { @@ -42,6 +39,9 @@ arch_thread_get_current_thread(void) } +#ifdef __x86_64__ + + static inline void arch_thread_set_current_thread(Thread* t) { @@ -59,18 +59,10 @@ arch_thread_set_current_thread(Thread* t) void arch_syscall_64_bit_return_value(void); -static inline Thread* -arch_thread_get_current_thread(void) -{ - Thread* t = (Thread*)x86_read_dr3(); - return t; -} - - static inline void arch_thread_set_current_thread(Thread* t) { - x86_write_dr3(t); + asm volatile("mov %0, %%gs:0" : : "r" (t) : "memory"); } @@ -82,3 +74,4 @@ arch_thread_set_current_thread(Thread* t) #endif #endif /* _KERNEL_ARCH_x86_THREAD_H */ + diff --git a/headers/private/kernel/arch/x86/arch_user_debugger.h b/headers/private/kernel/arch/x86/arch_user_debugger.h index 01a98e7639..c740c57dd4 100644 --- a/headers/private/kernel/arch/x86/arch_user_debugger.h +++ b/headers/private/kernel/arch/x86/arch_user_debugger.h @@ -9,12 +9,7 @@ #define ARCH_INIT_USER_DEBUG x86_init_user_debug // number of breakpoints the CPU supports -// On 32-bit, DR3 is used to hold the Thread*. -#ifdef __x86_64__ -# define X86_BREAKPOINT_COUNT 4 -#else -# define X86_BREAKPOINT_COUNT 3 -#endif +#define X86_BREAKPOINT_COUNT 4 // debug status register DR6 enum { diff --git a/headers/private/kernel/arch/x86/descriptors.h b/headers/private/kernel/arch/x86/descriptors.h index 30dc9f657f..5b16ab7754 100644 --- a/headers/private/kernel/arch/x86/descriptors.h +++ b/headers/private/kernel/arch/x86/descriptors.h @@ -9,6 +9,10 @@ #define _KERNEL_ARCH_x86_DESCRIPTORS_H +#define DPL_KERNEL 0 +#define DPL_USER 3 + + #ifndef _ASSEMBLER @@ -18,11 +22,6 @@ struct kernel_args; -enum descriptor_privilege_levels { - DPL_KERNEL = 0, - DPL_USER = 3, -}; - enum descriptor_types { // segment types DT_CODE_EXECUTE_ONLY = 0x8, @@ -48,6 +47,7 @@ enum gate_types { }; +void x86_descriptors_preboot_init_percpu(kernel_args* args, int cpu); void x86_descriptors_init(kernel_args* args); void x86_descriptors_init_percpu(kernel_args* args, int cpu); status_t x86_descriptors_init_post_vm(kernel_args* args); diff --git a/headers/private/kernel/arch/x86/msi.h b/headers/private/kernel/arch/x86/msi.h index 18685cb021..04e0cd9674 100644 --- a/headers/private/kernel/arch/x86/msi.h +++ b/headers/private/kernel/arch/x86/msi.h @@ -28,5 +28,6 @@ bool msi_supported(); status_t msi_allocate_vectors(uint8 count, uint8 *startVector, uint64 *address, uint16 *data); void msi_free_vectors(uint8 count, uint8 startVector); +void msi_assign_interrupt_to_cpu(uint8 irq, int32 cpu); #endif // _KERNEL_ARCH_x86_MSI_H diff --git a/headers/private/kernel/boot/kernel_args.h b/headers/private/kernel/boot/kernel_args.h index 95542b1cd3..1ebd5c1ef4 100644 --- a/headers/private/kernel/boot/kernel_args.h +++ b/headers/private/kernel/boot/kernel_args.h @@ -59,7 +59,7 @@ typedef struct kernel_args { uint64 ignored_physical_memory; uint32 num_cpus; - addr_range cpu_kstack[MAX_BOOT_CPUS]; + addr_range cpu_kstack[SMP_MAX_CPUS]; // boot volume KMessage data FixedWidthPointer boot_volume; diff --git a/headers/private/kernel/boot/platform/bios_ia32/platform_kernel_args.h b/headers/private/kernel/boot/platform/bios_ia32/platform_kernel_args.h index a191a0db14..31861be537 100644 --- a/headers/private/kernel/boot/platform/bios_ia32/platform_kernel_args.h +++ b/headers/private/kernel/boot/platform/bios_ia32/platform_kernel_args.h @@ -15,8 +15,8 @@ #include -// must match SMP_MAX_CPUS in arch_smp.h -#define MAX_BOOT_CPUS 8 +#define SMP_MAX_CPUS 64 + #define MAX_PHYSICAL_MEMORY_RANGE 32 #define MAX_PHYSICAL_ALLOCATED_RANGE 32 #define MAX_VIRTUAL_ALLOCATED_RANGE 32 diff --git a/headers/private/kernel/condition_variable.h b/headers/private/kernel/condition_variable.h index 9f4c0366b6..4e91baec22 100644 --- a/headers/private/kernel/condition_variable.h +++ b/headers/private/kernel/condition_variable.h @@ -56,19 +56,13 @@ public: void Publish(const void* object, const char* objectType); - void Unpublish(bool schedulerLocked = false); + void Unpublish(); - inline void NotifyOne(bool schedulerLocked = false, - status_t result = B_OK); - inline void NotifyAll(bool schedulerLocked = false, - status_t result = B_OK); + inline void NotifyOne(status_t result = B_OK); + inline void NotifyAll(status_t result = B_OK); - static void NotifyOne(const void* object, - bool schedulerLocked = false, - status_t result = B_OK); - static void NotifyAll(const void* object, - bool schedulerLocked = false, - status_t result = B_OK); + static void NotifyOne(const void* object, status_t result); + static void NotifyAll(const void* object, status_t result); // (both methods) caller must ensure that // the variable is not unpublished // concurrently @@ -86,8 +80,7 @@ public: void Dump() const; private: - void _Notify(bool all, bool schedulerLocked, - status_t result); + void _Notify(bool all, status_t result); void _NotifyLocked(bool all, status_t result); protected: @@ -124,16 +117,16 @@ ConditionVariableEntry::~ConditionVariableEntry() inline void -ConditionVariable::NotifyOne(bool schedulerLocked, status_t result) +ConditionVariable::NotifyOne(status_t result) { - _Notify(false, schedulerLocked, result); + _Notify(false, result); } inline void -ConditionVariable::NotifyAll(bool schedulerLocked, status_t result) +ConditionVariable::NotifyAll(status_t result) { - _Notify(true, schedulerLocked, result); + _Notify(true, result); } diff --git a/headers/private/kernel/cpu.h b/headers/private/kernel/cpu.h index 850e666913..dad23c6c56 100644 --- a/headers/private/kernel/cpu.h +++ b/headers/private/kernel/cpu.h @@ -11,15 +11,12 @@ #include +#include #include #include #include - -// define PAUSE, if not done in arch/cpu.h -#ifndef PAUSE -# define PAUSE() -#endif +#include struct kernel_args; @@ -31,20 +28,43 @@ namespace BKernel { using BKernel::Thread; +typedef enum cpu_topology_level { + CPU_TOPOLOGY_SMT, + CPU_TOPOLOGY_CORE, + CPU_TOPOLOGY_PACKAGE, + // + CPU_TOPOLOGY_LEVELS +} cpu_topology_level; + +typedef struct cpu_topology_node { + cpu_topology_level level; + + int id; + + cpu_topology_node** children; + int children_count; +} cpu_topology_node; + + /* CPU local data structure */ typedef struct cpu_ent { int cpu_num; // thread.c: used to force a reschedule at quantum expiration time - int preempted; + bool preempted; timer quantum_timer; // keeping track of CPU activity + seqlock active_time_lock; bigtime_t active_time; + bigtime_t irq_time; + bigtime_t interrupt_time; bigtime_t last_kernel_time; bigtime_t last_user_time; + int32 ici_counter; + // used in the kernel debugger addr_t fault_handler; addr_t fault_handler_stack_pointer; @@ -53,16 +73,24 @@ typedef struct cpu_ent { Thread* running_thread; Thread* previous_thread; bool invoke_scheduler; - bool invoke_scheduler_if_idle; bool disabled; + // CPU topology information + int topology_id[CPU_TOPOLOGY_LEVELS]; + int cache_id[CPU_MAX_CACHE_LEVEL]; + + // IRQs assigned to this CPU + struct list irqs; + spinlock irqs_lock; + // arch-specific stuff - arch_cpu_info arch; -} cpu_ent __attribute__((aligned(64))); + arch_cpu_info arch; +} cpu_ent CACHE_LINE_ALIGN; //extern cpu_ent gCPU[MAX_BOOT_CPUS]; extern cpu_ent gCPU[]; +extern uint32 gCPUCacheLevelCount; #ifdef __cplusplus @@ -79,6 +107,25 @@ bigtime_t cpu_get_active_time(int32 cpu); cpu_ent *get_cpu_struct(void); extern inline cpu_ent *get_cpu_struct(void) { return &gCPU[smp_get_current_cpu()]; } +status_t cpu_build_topology_tree(void); +const cpu_topology_node* get_cpu_topology(void); + +void cpu_set_scheduler_mode(enum scheduler_mode mode); + +status_t increase_cpu_performance(int delta); +status_t decrease_cpu_performance(int delta); + +void cpu_idle(void); +void cpu_wait(int32* variable, int32 test); + + +static inline void +cpu_pause(void) +{ + arch_cpu_pause(); +} + + void _user_clear_caches(void *address, size_t length, uint32 flags); bool _user_cpu_enabled(int32 cpu); status_t _user_set_cpu_enabled(int32 cpu, bool enabled); diff --git a/headers/private/kernel/int.h b/headers/private/kernel/int.h index b3642c4d80..91608a4782 100644 --- a/headers/private/kernel/int.h +++ b/headers/private/kernel/int.h @@ -12,6 +12,8 @@ #include #include +#include + // private install_io_interrupt_handler() flags #define B_NO_LOCK_VECTOR 0x100 #define B_NO_HANDLED_INFO 0x200 @@ -19,6 +21,28 @@ struct kernel_args; +enum interrupt_type { + INTERRUPT_TYPE_EXCEPTION, + INTERRUPT_TYPE_IRQ, + INTERRUPT_TYPE_LOCAL_IRQ, + INTERRUPT_TYPE_SYSCALL, + INTERRUPT_TYPE_ICI, + INTERRUPT_TYPE_UNKNOWN +}; + +struct irq_assignment { + list_link link; + + uint32 irq; + uint32 count; + + int32 handlers_count; + + int32 load; + int32 cpu; +}; + + #ifdef __cplusplus extern "C" { #endif @@ -53,8 +77,12 @@ are_interrupts_enabled(void) #define restore_interrupts(status) arch_int_restore_interrupts(status) -status_t reserve_io_interrupt_vectors(long count, long startVector); -status_t allocate_io_interrupt_vectors(long count, long *startVector); +status_t reserve_io_interrupt_vectors(long count, long startVector, + enum interrupt_type type); +status_t allocate_io_interrupt_vectors(long count, long *startVector, + enum interrupt_type type); void free_io_interrupt_vectors(long count, long startVector); +void assign_io_interrupt_to_cpu(long vector, int32 cpu); + #endif /* _KERNEL_INT_H */ diff --git a/headers/private/kernel/kscheduler.h b/headers/private/kernel/kscheduler.h index f106ac86c1..bfc6e0203d 100644 --- a/headers/private/kernel/kscheduler.h +++ b/headers/private/kernel/kscheduler.h @@ -1,4 +1,5 @@ /* + * Copyright 2013, Paweł Dziepak, pdziepak@quarnos.org. * Copyright 2008-2011, Ingo Weinhold, ingo_weinhold@gmx.de. * Copyright 2005-2010, Axel Dörfler, axeld@pinc-software.de. * Distributed under the terms of the MIT License. @@ -17,78 +18,69 @@ struct scheduling_analysis; struct SchedulerListener; -struct scheduler_ops { - /*! Enqueues the thread in the ready-to-run queue. - The caller must hold the scheduler lock (with disabled interrupts). - */ - void (*enqueue_in_run_queue)(Thread* thread); - - /*! Selects a thread from the ready-to-run queue and, if that's not the - calling thread, switches the current CPU's context to run the selected - thread. - If it's the same thread, the thread will just continue to run. - In either case, unless the thread is dead or is sleeping/waiting - indefinitely, the function will eventually return. - The caller must hold the scheduler lock (with disabled interrupts). - */ - void (*reschedule)(void); - - /*! Sets the given thread's priority. - The thread may be running or may be in the ready-to-run queue. - The caller must hold the scheduler lock (with disabled interrupts). - */ - void (*set_thread_priority)(Thread* thread, int32 priority); - bigtime_t (*estimate_max_scheduling_latency)(Thread* thread); - - /*! Called when the Thread structure is first created. - Per-thread housekeeping resources can be allocated. - Interrupts must be enabled. - */ - status_t (*on_thread_create)(Thread* thread, bool idleThread); - - /*! Called when a Thread structure is initialized and made ready for - use. - The per-thread housekeeping data structures are reset, if needed. - The caller must hold the scheduler lock (with disabled interrupts). - */ - void (*on_thread_init)(Thread* thread); - - /*! Called when a Thread structure is freed. - Frees up any per-thread resources allocated on the scheduler's part. The - function may be called even if on_thread_create() failed. - Interrupts must be enabled. - */ - void (*on_thread_destroy)(Thread* thread); - - /*! Called in the early boot process to start thread scheduling on the - current CPU. - The function is called once for each CPU. - Interrupts must be disabled, but the caller must not hold the scheduler - lock. - */ - void (*start)(void); -}; - -extern struct scheduler_ops* gScheduler; -extern spinlock gSchedulerLock; - -#define scheduler_enqueue_in_run_queue(thread) \ - gScheduler->enqueue_in_run_queue(thread) -#define scheduler_set_thread_priority(thread, priority) \ - gScheduler->set_thread_priority(thread, priority) -#define scheduler_reschedule() gScheduler->reschedule() -#define scheduler_start() gScheduler->start() -#define scheduler_on_thread_create(thread, idleThread) \ - gScheduler->on_thread_create(thread, idleThread) -#define scheduler_on_thread_init(thread) \ - gScheduler->on_thread_init(thread) -#define scheduler_on_thread_destroy(thread) \ - gScheduler->on_thread_destroy(thread) - #ifdef __cplusplus extern "C" { #endif +/*! Enqueues the thread in the ready-to-run queue. + The caller must hold the enqueued thread \c scheduler_lock. +*/ +void scheduler_enqueue_in_run_queue(Thread* thread); + +void scheduler_reschedule_ici(void); + +/*! Selects a thread from the ready-to-run queue and, if that's not the + calling thread, switches the current CPU's context to run the selected + thread. + If it's the same thread, the thread will just continue to run. + In either case, unless the thread is dead or is sleeping/waiting + indefinitely, the function will eventually return. + The caller must hold the current thread \c scheduler_lock. +*/ +void scheduler_reschedule(int32 next_state); + +/*! Sets the given thread's priority. + The thread may be running or may be in the ready-to-run queue. +*/ +int32 scheduler_set_thread_priority(Thread* thread, int32 priority); + +/*! Called when the Thread structure is first created. + Per-thread housekeeping resources can be allocated. + Interrupts must be enabled. +*/ +status_t scheduler_on_thread_create(Thread* thread, bool idleThread); + +/*! Called when a Thread structure is initialized and made ready for + use. + The per-thread housekeeping data structures are reset, if needed. +*/ +void scheduler_on_thread_init(Thread* thread); + +/*! Called when a Thread structure is freed. + Frees up any per-thread resources allocated on the scheduler's part. The + function may be called even if on_thread_create() failed. + Interrupts must be enabled. +*/ +void scheduler_on_thread_destroy(Thread* thread); + +/*! Called in the early boot process to start thread scheduling on the + current CPU. + The function is called once for each CPU. +*/ +void scheduler_start(void); + +/*! Sets scheduler operation mode. + */ +status_t scheduler_set_operation_mode(scheduler_mode mode); + +/*! Dumps scheduler specific thread information. +*/ +void scheduler_dump_thread_data(Thread* thread); + +void scheduler_new_thread_entry(Thread* thread); + +void scheduler_set_cpu_enabled(int32 cpu, bool enabled); + void scheduler_add_listener(struct SchedulerListener* listener); void scheduler_remove_listener(struct SchedulerListener* listener); @@ -99,6 +91,9 @@ bigtime_t _user_estimate_max_scheduling_latency(thread_id thread); status_t _user_analyze_scheduling(bigtime_t from, bigtime_t until, void* buffer, size_t size, struct scheduling_analysis* analysis); +status_t _user_set_scheduler_mode(int32 mode); +int32 _user_get_scheduler_mode(void); + #ifdef __cplusplus } #endif @@ -111,7 +106,7 @@ static inline void scheduler_reschedule_if_necessary_locked() { if (gCPU[smp_get_current_cpu()].invoke_scheduler) - scheduler_reschedule(); + scheduler_reschedule(B_THREAD_READY); } @@ -123,11 +118,14 @@ scheduler_reschedule_if_necessary() { if (are_interrupts_enabled()) { cpu_status state = disable_interrupts(); - acquire_spinlock(&gSchedulerLock); + + Thread* thread = get_cpu_struct()->running_thread; + acquire_spinlock(&thread->scheduler_lock); scheduler_reschedule_if_necessary_locked(); - release_spinlock(&gSchedulerLock); + release_spinlock(&thread->scheduler_lock); + restore_interrupts(state); } } diff --git a/headers/private/kernel/ksystem_info.h b/headers/private/kernel/ksystem_info.h index 9ff900cd33..1fc466d8ee 100644 --- a/headers/private/kernel/ksystem_info.h +++ b/headers/private/kernel/ksystem_info.h @@ -21,7 +21,11 @@ status_t system_info_init(struct kernel_args *args); status_t system_notifications_init(); const char* get_haiku_revision(void); -status_t _user_get_system_info(system_info *userInfo, size_t size); +status_t _user_get_system_info(system_info *userInfo); +status_t _user_get_cpu_info(uint32 firstCPU, uint32 cpuCount, cpu_info* info); +status_t _user_get_cpu_topology_info(cpu_topology_node_info* topologyInfos, + uint32* topologyInfoCount); + status_t _user_get_system_info_etc(int32 id, void *buffer, size_t bufferSize); diff --git a/headers/private/kernel/listeners.h b/headers/private/kernel/listeners.h index 64bb94d3d1..6406435325 100644 --- a/headers/private/kernel/listeners.h +++ b/headers/private/kernel/listeners.h @@ -34,7 +34,7 @@ struct SchedulerListener : DoublyLinkedListLinkImpl { typedef DoublyLinkedList SchedulerListenerList; extern SchedulerListenerList gSchedulerListeners; - // guarded by the thread spinlock +extern spinlock gSchedulerListenersLock; template diff --git a/headers/private/kernel/load_tracking.h b/headers/private/kernel/load_tracking.h new file mode 100644 index 0000000000..b4ff87a046 --- /dev/null +++ b/headers/private/kernel/load_tracking.h @@ -0,0 +1,57 @@ +/* + * Copyright 2013 Paweł Dziepak, pdziepak@quarnos.org. + * Distributed under the terms of the MIT License. + */ +#ifndef _KERNEL_LOAD_TRACKING_H +#define _KERNEL_LOAD_TRACKING_H + + +#include + + +const int32 kMaxLoad = 1000; +const bigtime_t kLoadMeasureInterval = 50000; +const bigtime_t kIntervalInaccuracy = kLoadMeasureInterval / 4; + + +static inline int32 +compute_load(bigtime_t& measureTime, bigtime_t& measureActiveTime, int32& load, + bigtime_t now) +{ + if (measureTime == 0) { + measureTime = now; + return -1; + } + + bigtime_t deltaTime = now - measureTime; + + if (deltaTime < kLoadMeasureInterval) + return -1; + + int32 oldLoad = load; + ASSERT(oldLoad >= 0 && oldLoad <= kMaxLoad); + + int32 newLoad = measureActiveTime * kMaxLoad; + newLoad /= max_c(deltaTime, 1); + newLoad = max_c(min_c(newLoad, kMaxLoad), 0); + + measureActiveTime = 0; + measureTime = now; + + deltaTime += kIntervalInaccuracy; + int n = deltaTime / kLoadMeasureInterval; + ASSERT(n > 0); + + if (n > 10) + load = newLoad; + else { + newLoad *= (1 << n) - 1; + load = (load + newLoad) / (1 << n); + ASSERT(load >= 0 && load <= kMaxLoad); + } + + return oldLoad; +} + + +#endif // _KERNEL_LOAD_TRACKING_H diff --git a/headers/private/kernel/lock.h b/headers/private/kernel/lock.h index 2a52c441d6..d3534aa188 100644 --- a/headers/private/kernel/lock.h +++ b/headers/private/kernel/lock.h @@ -9,7 +9,10 @@ #ifndef _KERNEL_LOCK_H #define _KERNEL_LOCK_H + #include + +#include #include @@ -18,6 +21,7 @@ struct mutex_waiter; typedef struct mutex { const char* name; struct mutex_waiter* waiters; + spinlock lock; #if KDEBUG thread_id holder; #else @@ -44,8 +48,9 @@ struct rw_lock_waiter; typedef struct rw_lock { const char* name; struct rw_lock_waiter* waiters; + spinlock lock; thread_id holder; - vint32 count; + int32 count; int32 owner_count; int16 active_readers; // Only > 0 while a writer is waiting: number @@ -88,14 +93,17 @@ typedef struct rw_lock { // static initializers #if KDEBUG -# define MUTEX_INITIALIZER(name) { name, NULL, -1, 0 } +# define MUTEX_INITIALIZER(name) \ + { name, NULL, B_SPINLOCK_INITIALIZER, -1, 0 } # define RECURSIVE_LOCK_INITIALIZER(name) { MUTEX_INITIALIZER(name), 0 } #else -# define MUTEX_INITIALIZER(name) { name, NULL, 0, 0, 0 } +# define MUTEX_INITIALIZER(name) \ + { name, NULL, B_SPINLOCK_INITIALIZER, 0, 0, 0 } # define RECURSIVE_LOCK_INITIALIZER(name) { MUTEX_INITIALIZER(name), -1, 0 } #endif -#define RW_LOCK_INITIALIZER(name) { name, NULL, -1, 0, 0, 0 } +#define RW_LOCK_INITIALIZER(name) \ + { name, NULL, B_SPINLOCK_INITIALIZER, -1, 0, 0, 0 } #if KDEBUG @@ -144,11 +152,11 @@ extern status_t mutex_switch_from_read_lock(rw_lock* from, mutex* to); extern status_t _rw_lock_read_lock(rw_lock* lock); extern status_t _rw_lock_read_lock_with_timeout(rw_lock* lock, uint32 timeoutFlags, bigtime_t timeout); -extern void _rw_lock_read_unlock(rw_lock* lock, bool schedulerLocked); -extern void _rw_lock_write_unlock(rw_lock* lock, bool schedulerLocked); +extern void _rw_lock_read_unlock(rw_lock* lock); +extern void _rw_lock_write_unlock(rw_lock* lock); -extern status_t _mutex_lock(mutex* lock, bool schedulerLocked); -extern void _mutex_unlock(mutex* lock, bool schedulerLocked); +extern status_t _mutex_lock(mutex* lock, void* locker); +extern void _mutex_unlock(mutex* lock); extern status_t _mutex_trylock(mutex* lock); extern status_t _mutex_lock_with_timeout(mutex* lock, uint32 timeoutFlags, bigtime_t timeout); @@ -191,7 +199,7 @@ rw_lock_read_unlock(rw_lock* lock) #else int32 oldCount = atomic_add(&lock->count, -1); if (oldCount >= RW_LOCK_WRITER_COUNT_BASE) - _rw_lock_read_unlock(lock, false); + _rw_lock_read_unlock(lock); #endif } @@ -199,7 +207,7 @@ rw_lock_read_unlock(rw_lock* lock) static inline void rw_lock_write_unlock(rw_lock* lock) { - _rw_lock_write_unlock(lock, false); + _rw_lock_write_unlock(lock); } @@ -207,23 +215,10 @@ static inline status_t mutex_lock(mutex* lock) { #if KDEBUG - return _mutex_lock(lock, false); + return _mutex_lock(lock, NULL); #else if (atomic_add(&lock->count, -1) < 0) - return _mutex_lock(lock, false); - return B_OK; -#endif -} - - -static inline status_t -mutex_lock_threads_locked(mutex* lock) -{ -#if KDEBUG - return _mutex_lock(lock, true); -#else - if (atomic_add(&lock->count, -1) < 0) - return _mutex_lock(lock, true); + return _mutex_lock(lock, NULL); return B_OK; #endif } @@ -261,7 +256,7 @@ mutex_unlock(mutex* lock) #if !KDEBUG if (atomic_add(&lock->count, 1) < -1) #endif - _mutex_unlock(lock, false); + _mutex_unlock(lock); } diff --git a/headers/private/kernel/smp.h b/headers/private/kernel/smp.h index aa19ad35d9..43126eb697 100644 --- a/headers/private/kernel/smp.h +++ b/headers/private/kernel/smp.h @@ -9,8 +9,15 @@ #define KERNEL_SMP_H +#include +#include +#include + #include +#include + + struct kernel_args; @@ -22,8 +29,7 @@ enum { SMP_MSG_GLOBAL_INVALIDATE_PAGES, SMP_MSG_CPU_HALT, SMP_MSG_CALL_FUNCTION, - SMP_MSG_RESCHEDULE, - SMP_MSG_RESCHEDULE_IF_IDLE + SMP_MSG_RESCHEDULE }; enum { @@ -32,10 +38,28 @@ enum { SMP_MSG_FLAG_FREE_ARG = 0x2, }; -typedef uint32 cpu_mask_t; - typedef void (*smp_call_func)(addr_t data1, int32 currentCPU, addr_t data2, addr_t data3); +class CPUSet { +public: + inline CPUSet(); + + inline void ClearAll(); + inline void SetAll(); + + inline void SetBit(int32 cpu); + inline void ClearBit(int32 cpu); + + inline bool GetBit(int32 cpu) const; + + inline bool IsEmpty() const; + +private: + static const int kArraySize = ROUNDUP(SMP_MAX_CPUS, 32) / 32; + + uint32 fBitmap[kArraySize]; +}; + #ifdef __cplusplus extern "C" { @@ -48,10 +72,10 @@ status_t smp_per_cpu_init(struct kernel_args *args, int32 cpu); status_t smp_init_post_generic_syscalls(void); bool smp_trap_non_boot_cpus(int32 cpu, uint32* rendezVous); void smp_wake_up_non_boot_cpus(void); -void smp_cpu_rendezvous(volatile uint32 *var, int current_cpu); +void smp_cpu_rendezvous(uint32* var); void smp_send_ici(int32 targetCPU, int32 message, addr_t data, addr_t data2, addr_t data3, void *data_ptr, uint32 flags); -void smp_send_multicast_ici(cpu_mask_t cpuMask, int32 message, addr_t data, +void smp_send_multicast_ici(CPUSet& cpuMask, int32 message, addr_t data, addr_t data2, addr_t data3, void *data_ptr, uint32 flags); void smp_send_broadcast_ici(int32 message, addr_t data, addr_t data2, addr_t data3, void *data_ptr, uint32 flags); @@ -69,6 +93,63 @@ int smp_intercpu_int_handler(int32 cpu); #endif +inline +CPUSet::CPUSet() +{ + memset(fBitmap, 0, sizeof(fBitmap)); +} + + +inline void +CPUSet::ClearAll() +{ + memset(fBitmap, 0, sizeof(fBitmap)); +} + + +inline void +CPUSet::SetAll() +{ + memset(fBitmap, ~uint8(0), sizeof(fBitmap)); +} + + +inline void +CPUSet::SetBit(int32 cpu) +{ + int32* element = (int32*)&fBitmap[cpu % kArraySize]; + atomic_or(element, 1u << (cpu / kArraySize)); +} + + +inline void +CPUSet::ClearBit(int32 cpu) +{ + int32* element = (int32*)&fBitmap[cpu % kArraySize]; + atomic_and(element, ~uint32(1u << (cpu / kArraySize))); +} + + +inline bool +CPUSet::GetBit(int32 cpu) const +{ + int32* element = (int32*)&fBitmap[cpu % kArraySize]; + return ((uint32)atomic_get(element) & (1u << (cpu / kArraySize))) != 0; +} + + +inline bool +CPUSet::IsEmpty() const +{ + for (int i = 0; i < kArraySize; i++) { + if (fBitmap[i] != 0) + return false; + } + + return true; +} + + // Unless spinlock debug features are enabled, try to inline // {acquire,release}_spinlock(). #if !DEBUG_SPINLOCKS && !B_DEBUG_SPINLOCK_CONTENTION @@ -77,7 +158,7 @@ int smp_intercpu_int_handler(int32 cpu); static inline bool try_acquire_spinlock_inline(spinlock* lock) { - return atomic_or((int32*)lock, 1) == 0; + return atomic_get_and_set((int32*)lock, 1) == 0; } @@ -93,7 +174,7 @@ acquire_spinlock_inline(spinlock* lock) static inline void release_spinlock_inline(spinlock* lock) { - atomic_and((int32*)lock, 0); + atomic_set((int32*)lock, 0); } @@ -101,6 +182,108 @@ release_spinlock_inline(spinlock* lock) #define acquire_spinlock(lock) acquire_spinlock_inline(lock) #define release_spinlock(lock) release_spinlock_inline(lock) + +static inline bool +try_acquire_write_spinlock_inline(rw_spinlock* lock) +{ + return atomic_test_and_set(&lock->lock, 1u << 31, 0) == 0; +} + + +static inline void +acquire_write_spinlock_inline(rw_spinlock* lock) +{ + if (try_acquire_write_spinlock(lock)) + return; + acquire_write_spinlock(lock); +} + + +static inline void +release_write_spinlock_inline(rw_spinlock* lock) +{ + atomic_set(&lock->lock, 0); +} + + +static inline bool +try_acquire_read_spinlock_inline(rw_spinlock* lock) +{ + uint32 previous = atomic_add(&lock->lock, 1); + return (previous & (1u << 31)) == 0; +} + + +static inline void +acquire_read_spinlock_inline(rw_spinlock* lock) +{ + if (try_acquire_read_spinlock(lock)) + return; + acquire_read_spinlock(lock); +} + + +static inline void +release_read_spinlock_inline(rw_spinlock* lock) +{ + atomic_add(&lock->lock, -1); +} + + +#define try_acquire_read_spinlock(lock) try_acquire_read_spinlock_inline(lock) +#define acquire_read_spinlock(lock) acquire_read_spinlock_inline(lock) +#define release_read_spinlock(lock) release_read_spinlock_inline(lock) +#define try_acquire_write_spinlock(lock) \ + try_acquire_write_spinlock(lock) +#define acquire_write_spinlock(lock) acquire_write_spinlock_inline(lock) +#define release_write_spinlock(lock) release_write_spinlock_inline(lock) + + +static inline bool +try_acquire_write_seqlock_inline(seqlock* lock) { + bool succeed = try_acquire_spinlock(&lock->lock); + if (succeed) + atomic_add((int32*)&lock->count, 1); + return succeed; +} + + +static inline void +acquire_write_seqlock_inline(seqlock* lock) { + acquire_spinlock(&lock->lock); + atomic_add((int32*)&lock->count, 1); +} + + +static inline void +release_write_seqlock_inline(seqlock* lock) { + atomic_add((int32*)&lock->count, 1); + release_spinlock(&lock->lock); +} + + +static inline uint32 +acquire_read_seqlock_inline(seqlock* lock) { + return atomic_get((int32*)&lock->count); +} + + +static inline bool +release_read_seqlock_inline(seqlock* lock, uint32 count) { + uint32 current = atomic_get((int32*)&lock->count); + + return count % 2 == 0 && current == count; +} + + +#define try_acquire_write_seqlock(lock) try_acquire_write_seqlock_inline(lock) +#define acquire_write_seqlock(lock) acquire_write_seqlock_inline(lock) +#define release_write_seqlock(lock) release_write_seqlock_inline(lock) +#define acquire_read_seqlock(lock) acquire_read_seqlock_inline(lock) +#define release_read_seqlock(lock, count) \ + release_read_seqlock_inline(lock, count) + + #endif // !DEBUG_SPINLOCKS && !B_DEBUG_SPINLOCK_CONTENTION diff --git a/headers/private/kernel/team.h b/headers/private/kernel/team.h index ce09ea470a..2fb555e493 100644 --- a/headers/private/kernel/team.h +++ b/headers/private/kernel/team.h @@ -46,7 +46,7 @@ thread_id load_image_etc(int32 argCount, const char* const* args, const char* const* env, int32 priority, team_id parentID, uint32 flags); void team_set_job_control_state(Team* team, job_control_state newState, - Signal* signal, bool threadsLocked); + Signal* signal); void team_set_controlling_tty(int32 index); int32 team_get_controlling_tty(); status_t team_set_foreground_process_group(int32 ttyIndex, pid_t processGroup); diff --git a/headers/private/kernel/thread.h b/headers/private/kernel/thread.h index 8d1287e172..f502c94251 100644 --- a/headers/private/kernel/thread.h +++ b/headers/private/kernel/thread.h @@ -11,12 +11,13 @@ #include -#include -#include +#include +#include // For the thread blocking inline functions only. #include #include +#include struct arch_fork_arg; @@ -69,15 +70,13 @@ public: using BKernel::ThreadCreationAttributes; +extern spinlock gThreadCreationLock; + + #ifdef __cplusplus extern "C" { #endif -void thread_enqueue(Thread *t, struct thread_queue *q); -Thread *thread_lookat_queue(struct thread_queue *q); -Thread *thread_dequeue(struct thread_queue *q); -Thread *thread_dequeue_id(struct thread_queue *q, thread_id id); - void thread_at_kernel_entry(bigtime_t now); // called when the thread enters the kernel on behalf of the thread void thread_at_kernel_exit(void); @@ -86,9 +85,11 @@ void thread_reset_for_exec(void); status_t thread_init(struct kernel_args *args); status_t thread_preboot_init_percpu(struct kernel_args *args, int32 cpuNum); -void thread_yield(bool force); +void thread_yield(void); void thread_exit(void); +void thread_map(void (*function)(Thread* thread, void* data), void* data); + int32 thread_max_threads(void); int32 thread_used_threads(void); @@ -135,8 +136,7 @@ status_t deselect_thread(int32 object, struct select_info *info, bool kernel); status_t thread_block(); status_t thread_block_with_timeout(uint32 timeoutFlags, bigtime_t timeout); -status_t thread_block_with_timeout_locked(uint32 timeoutFlags, - bigtime_t timeout); +void thread_unblock(Thread* thread, status_t status); // used in syscalls.c status_t _user_set_thread_priority(thread_id thread, int32 newPriority); @@ -212,7 +212,7 @@ thread_is_interrupted(Thread* thread, uint32 flags) static inline bool thread_is_blocked(Thread* thread) { - return thread->wait.status == 1; + return atomic_get(&thread->wait.status) == 1; } @@ -234,22 +234,22 @@ thread_is_blocked(Thread* thread) If a client lock other than the scheduler lock is used, this function must be called with that lock being held. Afterwards that lock should be dropped and the function that actually blocks the thread shall be invoked - (thread_block[_locked]() or thread_block_with_timeout[_locked]()). In - between these two steps no functionality that uses the thread blocking API - for this thread shall be used. + (thread_block[_locked]() or thread_block_with_timeout()). In between these + two steps no functionality that uses the thread blocking API for this thread + shall be used. When the caller determines that the condition for unblocking the thread occurred, it calls thread_unblock_locked() to unblock the thread. At that time one of locks that are held when calling thread_prepare_to_block() must be held. Usually that would be the client lock. In two cases it generally isn't, however, since the unblocking code doesn't know about the client - lock: 1. When thread_block_with_timeout[_locked]() had been used and the - timeout occurs. 2. When thread_prepare_to_block() had been called with one - or both of the \c B_CAN_INTERRUPT or \c B_KILL_CAN_INTERRUPT flags specified - and someone calls thread_interrupt() that is supposed to wake up the thread. + lock: 1. When thread_block_with_timeout() had been used and the timeout + occurs. 2. When thread_prepare_to_block() had been called with one or both + of the \c B_CAN_INTERRUPT or \c B_KILL_CAN_INTERRUPT flags specified and + someone calls thread_interrupt() that is supposed to wake up the thread. In either of these two cases only the scheduler lock is held by the unblocking code. A timeout can only happen after - thread_block_with_timeout_locked() has been called, but an interruption is + thread_block_with_timeout() has been called, but an interruption is possible at any time. The client code must deal with those situations. Generally blocking and unblocking threads proceed in the following manner: @@ -333,39 +333,6 @@ thread_prepare_to_block(Thread* thread, uint32 flags, uint32 type, } -/*! Blocks the current thread. - - The thread is blocked until someone else unblock it. Must be called after a - call to thread_prepare_to_block(). If the thread has already been unblocked - after the previous call to thread_prepare_to_block(), this function will - return immediately. Cf. the documentation of thread_prepare_to_block() for - more details. - - The caller must hold the scheduler lock. - - \param thread The current thread. - \return The error code passed to the unblocking function. thread_interrupt() - uses \c B_INTERRUPTED. By convention \c B_OK means that the wait was - successful while another error code indicates a failure (what that means - depends on the client code). -*/ -static inline status_t -thread_block_locked(Thread* thread) -{ - if (thread->wait.status == 1) { - // check for signals, if interruptible - if (thread_is_interrupted(thread, thread->wait.flags)) { - thread->wait.status = B_INTERRUPTED; - } else { - thread->next_state = B_THREAD_WAITING; - scheduler_reschedule(); - } - } - - return thread->wait.status; -} - - /*! Unblocks the specified blocked thread. If the thread is no longer waiting (e.g. because thread_unblock_locked() has @@ -417,10 +384,12 @@ thread_unblock_locked(Thread* thread, status_t status) static inline status_t thread_interrupt(Thread* thread, bool kill) { - if ((thread->wait.flags & B_CAN_INTERRUPT) != 0 - || (kill && (thread->wait.flags & B_KILL_CAN_INTERRUPT) != 0)) { - thread_unblock_locked(thread, B_INTERRUPTED); - return B_OK; + if (thread_is_blocked(thread)) { + if ((thread->wait.flags & B_CAN_INTERRUPT) != 0 + || (kill && (thread->wait.flags & B_KILL_CAN_INTERRUPT) != 0)) { + thread_unblock_locked(thread, B_INTERRUPTED); + return B_OK; + } } return B_NOT_ALLOWED; diff --git a/headers/private/kernel/thread_types.h b/headers/private/kernel/thread_types.h index 1c06271a50..eb7f1ad5e1 100644 --- a/headers/private/kernel/thread_types.h +++ b/headers/private/kernel/thread_types.h @@ -57,12 +57,15 @@ struct cpu_ent; struct image; // defined in image.c struct io_context; struct realtime_sem_context; // defined in realtime_sem.cpp -struct scheduler_thread_data; struct select_info; struct user_thread; // defined in libroot/user_thread.h struct VMAddressSpace; struct xsi_sem_context; // defined in xsi_semaphore.cpp +namespace Scheduler { + struct ThreadData; +} + namespace BKernel { struct Team; struct Thread; @@ -242,10 +245,10 @@ struct Team : TeamThreadIteratorEntry, KernelReferenceable, struct job_control_entry* job_control_entry; VMAddressSpace *address_space; - Thread *main_thread; // protected by fLock and the scheduler - // lock (and the thread's lock), immutable + Thread *main_thread; // protected by fLock, immutable // after first set - Thread *thread_list; // protected by fLock and the scheduler lock + Thread *thread_list; // protected by fLock, signal_lock and + // gThreadCreationLock struct team_loading_info *loading_info; // protected by fLock struct list image_list; // protected by sImageMutex struct list watcher_list; @@ -263,13 +266,13 @@ struct Team : TeamThreadIteratorEntry, KernelReferenceable, struct team_debug_info debug_info; - // protected by scheduler lock + // protected by time_lock bigtime_t dead_threads_kernel_time; bigtime_t dead_threads_user_time; bigtime_t cpu_clock_offset; + spinlock time_lock; - // user group information; protected by fLock, the *_uid/*_gid fields also - // by the scheduler lock + // user group information; protected by fLock uid_t saved_set_uid; uid_t real_uid; uid_t effective_uid; @@ -290,6 +293,8 @@ struct Team : TeamThreadIteratorEntry, KernelReferenceable, bool initialized; // true when the state has been initialized } exit; + spinlock signal_lock; + public: ~Team(); @@ -397,7 +402,7 @@ private: BKernel::QueuedSignalsCounter* fQueuedSignalsCounter; BKernel::PendingSignals fPendingSignals; - // protected by scheduler lock + // protected by signal_lock struct sigaction fSignalActions[MAX_SIGNAL_NUMBER]; // indexed signal - 1, protected by fLock @@ -405,7 +410,7 @@ private: TeamTimeUserTimerList fCPUTimeUserTimers; // protected by scheduler lock TeamUserTimeUserTimerList fUserTimeUserTimers; - vint32 fUserDefinedTimerCount; // accessed atomically + int32 fUserDefinedTimerCount; // accessed atomically }; @@ -416,20 +421,17 @@ struct Thread : TeamThreadIteratorEntry, KernelReferenceable { int64 serial_number; // immutable after adding thread to hash Thread *hash_next; // protected by thread hash lock Thread *team_next; // protected by team lock and fLock - Thread *queue_next; // protected by scheduler lock - timer alarm; // protected by scheduler lock char name[B_OS_NAME_LENGTH]; // protected by fLock int32 priority; // protected by scheduler lock - int32 next_priority; // protected by scheduler lock int32 io_priority; // protected by fLock int32 state; // protected by scheduler lock - int32 next_state; // protected by scheduler lock struct cpu_ent *cpu; // protected by scheduler lock struct cpu_ent *previous_cpu; // protected by scheduler lock int32 pinned_to_cpu; // only accessed by this thread or in the // scheduler, when thread is not running + spinlock scheduler_lock; - sigset_t sig_block_mask; // protected by scheduler lock, + sigset_t sig_block_mask; // protected by team->signal_lock, // only modified by the thread itself sigset_t sigsuspend_original_unblocked_mask; // non-0 after a return from _user_sigsuspend(), containing the inverted @@ -442,8 +444,8 @@ struct Thread : TeamThreadIteratorEntry, KernelReferenceable { bool in_kernel; // protected by time_lock, only written by // this thread - bool was_yielded; // protected by scheduler lock - struct scheduler_thread_data* scheduler_data; // protected by scheduler lock + bool has_yielded; // protected by scheduler lock + Scheduler::ThreadData* scheduler_data; // protected by scheduler lock struct user_thread* user_thread; // write-protected by fLock, only // modified by the thread itself and @@ -481,7 +483,8 @@ struct Thread : TeamThreadIteratorEntry, KernelReferenceable { /* this field may only stay in debug builds in the future */ BKernel::Team *team; // protected by team lock, thread lock, scheduler - // lock + // lock, team_lock + rw_spinlock team_lock; struct { sem_id sem; // immutable after thread creation @@ -514,7 +517,7 @@ struct Thread : TeamThreadIteratorEntry, KernelReferenceable { bigtime_t user_time; // protected by time_lock bigtime_t kernel_time; // protected by time_lock bigtime_t last_time; // protected by time_lock - bigtime_t cpu_clock_offset; // protected by scheduler lock + bigtime_t cpu_clock_offset; // protected by time_lock void (*post_interrupt_callback)(void*); void* post_interrupt_data; @@ -604,11 +607,11 @@ private: mutex fLock; BKernel::PendingSignals fPendingSignals; - // protected by scheduler lock + // protected by team->signal_lock UserTimerList fUserTimers; // protected by fLock ThreadTimeUserTimerList fCPUTimeUserTimers; - // protected by scheduler lock + // protected by time_lock }; @@ -747,7 +750,7 @@ Thread::DequeuePendingSignal(sigset_t nonBlocked, Signal& buffer) /*! Returns the thread's current total CPU time (kernel + user + offset). - The caller must hold the scheduler lock. + The caller must hold \c time_lock. \param ignoreCurrentRun If \c true and the thread is currently running, don't add the time since the last time \c last_time was updated. Should @@ -762,7 +765,7 @@ Thread::CPUTime(bool ignoreCurrentRun) const // If currently running, also add the time since the last check, unless // requested otherwise. - if (!ignoreCurrentRun && cpu != NULL) + if (!ignoreCurrentRun && last_time != 0) time += system_time() - last_time; return time; @@ -780,12 +783,6 @@ using BKernel::ProcessGroup; using BKernel::ProcessGroupList; -struct thread_queue { - Thread* head; - Thread* tail; -}; - - #endif // !_ASSEMBLER diff --git a/headers/private/kernel/timer.h b/headers/private/kernel/timer.h index 2789b56493..a1c91af824 100644 --- a/headers/private/kernel/timer.h +++ b/headers/private/kernel/timer.h @@ -23,13 +23,8 @@ struct kernel_args; #define B_TIMER_USE_TIMER_STRUCT_TIMES 0x4000 // For add_timer(): Use the timer::schedule_time (absolute time) and // timer::period values instead of the period parameter. -#define B_TIMER_ACQUIRE_SCHEDULER_LOCK 0x8000 - // The timer hook is invoked with the scheduler lock held. When invoking - // cancel_timer() with the scheduler lock held, too, this helps to avoid - // race conditions. #define B_TIMER_FLAGS \ - (B_TIMER_USE_TIMER_STRUCT_TIMES | B_TIMER_ACQUIRE_SCHEDULER_LOCK \ - | B_TIMER_REAL_TIME_BASE) + (B_TIMER_USE_TIMER_STRUCT_TIMES | B_TIMER_REAL_TIME_BASE) /* Timer info structure */ struct timer_info { diff --git a/headers/private/kernel/user_debugger.h b/headers/private/kernel/user_debugger.h index 777483388b..809289c445 100644 --- a/headers/private/kernel/user_debugger.h +++ b/headers/private/kernel/user_debugger.h @@ -68,7 +68,7 @@ struct team_debug_info { thread_id causing_thread; // thread that caused the debugger to be attached; -1 for manual // debugger attachment (or no debugger installed) - vint32 image_event; + int32 image_event; // counter incremented whenever an image is created/deleted struct ConditionVariable* debugger_changed_condition; diff --git a/headers/private/kernel/util/AutoLock.h b/headers/private/kernel/util/AutoLock.h index 12f9b972b4..3151065857 100644 --- a/headers/private/kernel/util/AutoLock.h +++ b/headers/private/kernel/util/AutoLock.h @@ -160,6 +160,144 @@ private: typedef AutoLocker InterruptsSpinLocker; +class ReadSpinLocking { +public: + inline bool Lock(rw_spinlock* lockable) + { + acquire_read_spinlock(lockable); + return true; + } + + inline void Unlock(rw_spinlock* lockable) + { + release_read_spinlock(lockable); + } +}; + +typedef AutoLocker ReadSpinLocker; + + +class InterruptsReadSpinLocking { +public: + InterruptsReadSpinLocking() + : + fState(0) + { + } + + inline bool Lock(rw_spinlock* lockable) + { + fState = disable_interrupts(); + acquire_read_spinlock(lockable); + return true; + } + + inline void Unlock(rw_spinlock* lockable) + { + release_read_spinlock(lockable); + restore_interrupts(fState); + } + +private: + int fState; +}; + +typedef AutoLocker + InterruptsReadSpinLocker; + + +class WriteSpinLocking { +public: + inline bool Lock(rw_spinlock* lockable) + { + acquire_write_spinlock(lockable); + return true; + } + + inline void Unlock(rw_spinlock* lockable) + { + release_write_spinlock(lockable); + } +}; + +typedef AutoLocker WriteSpinLocker; + + +class InterruptsWriteSpinLocking { +public: + InterruptsWriteSpinLocking() + : + fState(0) + { + } + + inline bool Lock(rw_spinlock* lockable) + { + fState = disable_interrupts(); + acquire_write_spinlock(lockable); + return true; + } + + inline void Unlock(rw_spinlock* lockable) + { + release_write_spinlock(lockable); + restore_interrupts(fState); + } + +private: + int fState; +}; + +typedef AutoLocker + InterruptsWriteSpinLocker; + + +class WriteSequentialLocking { +public: + inline bool Lock(seqlock* lockable) + { + acquire_write_seqlock(lockable); + return true; + } + + inline void Unlock(seqlock* lockable) + { + release_write_seqlock(lockable); + } +}; + +typedef AutoLocker WriteSequentialLocker; + + +class InterruptsWriteSequentialLocking { +public: + InterruptsWriteSequentialLocking() + : + fState(0) + { + } + + inline bool Lock(seqlock* lockable) + { + fState = disable_interrupts(); + acquire_write_seqlock(lockable); + return true; + } + + inline void Unlock(seqlock* lockable) + { + release_write_seqlock(lockable); + restore_interrupts(fState); + } + +private: + int fState; +}; + +typedef AutoLocker + InterruptsWriteSequentialLocker; + + class ThreadCPUPinLocking { public: inline bool Lock(Thread* thread) @@ -191,6 +329,12 @@ using BPrivate::WriteLocker; using BPrivate::InterruptsLocker; using BPrivate::SpinLocker; using BPrivate::InterruptsSpinLocker; +using BPrivate::ReadSpinLocker; +using BPrivate::InterruptsReadSpinLocker; +using BPrivate::WriteSpinLocker; +using BPrivate::InterruptsWriteSpinLocker; +using BPrivate::WriteSequentialLocker; +using BPrivate::InterruptsWriteSequentialLocker; using BPrivate::ThreadCPUPinner; using BPrivate::TeamLocker; using BPrivate::ThreadLocker; diff --git a/headers/private/kernel/util/BitUtils.h b/headers/private/kernel/util/BitUtils.h new file mode 100644 index 0000000000..55191d0079 --- /dev/null +++ b/headers/private/kernel/util/BitUtils.h @@ -0,0 +1,60 @@ +/* + * Copyright 2013 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ +#ifndef KERNEL_UTIL_BITUTIL_H +#define KERNEL_UTIL_BITUTIL_H + + +#include + + +// http://graphics.stanford.edu/~seander/bithacks.html +static inline uint32 +next_power_of_2(uint32 v) +{ + v--; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + v++; + + return v; +} + + +// http://graphics.stanford.edu/~seander/bithacks.html +static inline uint32 +count_set_bits(uint32 v) +{ + v = v - ((v >> 1) & 0x55555555); + v = (v & 0x33333333) + ((v >> 2) & 0x33333333); + return (((v + (v >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24; +} + + +static inline uint32 +log2(uint32 v) +{ + static const int MultiplyDeBruijnBitPosition[32] = { + 0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, + 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31 + }; + + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + + return MultiplyDeBruijnBitPosition[(uint32)(v * 0x07C4ACDDU) >> 27]; +} + + +#endif // KERNEL_UTIL_RANDOM_H + diff --git a/headers/private/kernel/util/Bitmap.h b/headers/private/kernel/util/Bitmap.h new file mode 100644 index 0000000000..08114715db --- /dev/null +++ b/headers/private/kernel/util/Bitmap.h @@ -0,0 +1,82 @@ +/* + * Copyright 2013 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ +#ifndef KERNEL_UTIL_BITMAP_H +#define KERNEL_UTIL_BITMAP_H + + +#include + +#include + + +class Bitmap { +public: + Bitmap(int bitCount); + ~Bitmap(); + + inline status_t GetInitStatus(); + + inline bool Get(int index) const; + inline void Set(int index); + inline void Clear(int index); + + int GetHighestSet() const; + +private: + status_t fInitStatus; + + int fElementsCount; + int fSize; + addr_t* fBits; + + static const int kBitsPerElement; +}; + + +status_t +Bitmap::GetInitStatus() +{ + return fInitStatus; +} + + +bool +Bitmap::Get(int index) const +{ + ASSERT(index < fSize); + + const int kArrayElement = index / kBitsPerElement; + const addr_t kBitMask = addr_t(1) << (index % kBitsPerElement); + return fBits[kArrayElement] & kBitMask; +} + + +void +Bitmap::Set(int index) +{ + ASSERT(index < fSize); + + const int kArrayElement = index / kBitsPerElement; + const addr_t kBitMask = addr_t(1) << (index % kBitsPerElement); + fBits[kArrayElement] |= kBitMask; +} + + +void +Bitmap::Clear(int index) +{ + ASSERT(index < fSize); + + const int kArrayElement = index / kBitsPerElement; + const addr_t kBitMask = addr_t(1) << (index % kBitsPerElement); + fBits[kArrayElement] &= ~addr_t(kBitMask); +} + + +#endif // KERNEL_UTIL_BITMAP_H + diff --git a/headers/private/kernel/util/Heap.h b/headers/private/kernel/util/Heap.h new file mode 100644 index 0000000000..cecc5a5eb7 --- /dev/null +++ b/headers/private/kernel/util/Heap.h @@ -0,0 +1,357 @@ +/* + * Copyright 2013 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ +#ifndef KERNEL_UTIL_HEAP_H +#define KERNEL_UTIL_HEAP_H + + +#include + +#include + + +template +struct HeapLink { + HeapLink(); + + int fIndex; + Key fKey; +}; + +template +class HeapLinkImpl { +private: + typedef HeapLink Link; + +public: + inline Link* GetHeapLink(); + +private: + Link fHeapLink; +}; + +template +class HeapStandardGetLink { +private: + typedef HeapLink Link; + +public: + inline Link* operator()(Element* element) const; +}; + +template Element::*LinkMember> +class HeapMemberGetLink { +private: + typedef HeapLink Link; + +public: + inline Link* operator()(Element* element) const; +}; + +template +class HeapLesserCompare { +public: + inline bool operator()(Key a, Key b); +}; + +template +class HeapGreaterCompare { +public: + inline bool operator()(Key a, Key b); +}; + +#define HEAP_TEMPLATE_LIST \ + template +#define HEAP_CLASS_NAME Heap + +template, + typename GetLink = HeapStandardGetLink > +class Heap { +public: + Heap(); + Heap(int initialSize); + ~Heap(); + + inline Element* PeekRoot() const; + + static const Key& GetKey(Element* element); + + inline void ModifyKey(Element* element, Key newKey); + + inline void RemoveRoot(); + inline status_t Insert(Element* element, Key key); + +private: + status_t _GrowHeap(int minimalSize = 0); + + void _MoveUp(HeapLink* link); + void _MoveDown(HeapLink* link); + + Element** fElements; + int fLastElement; + int fSize; + + static Compare sCompare; + static GetLink sGetLink; +}; + + +#if KDEBUG +template +HeapLink::HeapLink() + : + fIndex(-1) +{ +} +#else +template +HeapLink::HeapLink() +{ +} +#endif + + +template +HeapLink* +HeapLinkImpl::GetHeapLink() +{ + return &fHeapLink; +} + + +template +HeapLink* +HeapStandardGetLink::operator()(Element* element) const +{ + return element->GetHeapLink(); +} + + +template Element::*LinkMember> +HeapLink* +HeapMemberGetLink::operator()(Element* element) const +{ + return &(element->*LinkMember); +} + + +template +bool +HeapLesserCompare::operator()(Key a, Key b) +{ + return a < b; +} + + +template +bool +HeapGreaterCompare::operator()(Key a, Key b) +{ + return a > b; +} + + +HEAP_TEMPLATE_LIST +HEAP_CLASS_NAME::Heap() + : + fElements(NULL), + fLastElement(0), + fSize(0) +{ +} + + +HEAP_TEMPLATE_LIST +HEAP_CLASS_NAME::Heap(int initialSize) + : + fElements(NULL), + fLastElement(0), + fSize(0) +{ + _GrowHeap(initialSize); +} + + +HEAP_TEMPLATE_LIST +HEAP_CLASS_NAME::~Heap() +{ + free(fElements); +} + + +HEAP_TEMPLATE_LIST +Element* +HEAP_CLASS_NAME::PeekRoot() const +{ + if (fLastElement > 0) + return fElements[0]; + return NULL; +} + + +HEAP_TEMPLATE_LIST +const Key& +HEAP_CLASS_NAME::GetKey(Element* element) +{ + return sGetLink(element)->fKey; +} + + +HEAP_TEMPLATE_LIST +void +HEAP_CLASS_NAME::ModifyKey(Element* element, Key newKey) +{ + HeapLink* link = sGetLink(element); + + ASSERT(link->fIndex >= 0 && link->fIndex < fLastElement); + Key oldKey = link->fKey; + link->fKey = newKey; + + if (sCompare(newKey, oldKey)) + _MoveUp(link); + else if (sCompare(oldKey, newKey)) + _MoveDown(link); +} + + +HEAP_TEMPLATE_LIST +void +HEAP_CLASS_NAME::RemoveRoot() +{ + ASSERT(fLastElement > 0); + +#if KDEBUG + Element* element = PeekRoot(); + HeapLink* link = sGetLink(element); + ASSERT(link->fIndex != -1); + link->fIndex = -1; +#endif + + fLastElement--; + if (fLastElement > 0) { + Element* lastElement = fElements[fLastElement]; + fElements[0] = lastElement; + sGetLink(lastElement)->fIndex = 0; + _MoveDown(sGetLink(lastElement)); + } +} + + +HEAP_TEMPLATE_LIST +status_t +HEAP_CLASS_NAME::Insert(Element* element, Key key) +{ + if (fLastElement == fSize) { + status_t result = _GrowHeap(); + if (result != B_OK) + return result; + } + + ASSERT(fLastElement != fSize); + + HeapLink* link = sGetLink(element); + + ASSERT(link->fIndex == -1); + + fElements[fLastElement] = element; + link->fIndex = fLastElement++; + link->fKey = key; + _MoveUp(link); + + return B_OK; +} + + +HEAP_TEMPLATE_LIST +status_t +HEAP_CLASS_NAME::_GrowHeap(int minimalSize) +{ + int newSize = max_c(max_c(fSize * 2, 4), minimalSize); + + size_t arraySize = newSize * sizeof(Element*); + Element** newBuffer + = reinterpret_cast(realloc(fElements, arraySize)); + if (newBuffer == NULL) + return B_NO_MEMORY; + + fElements = newBuffer; + fSize = newSize; + + return B_OK; +} + + +HEAP_TEMPLATE_LIST +void +HEAP_CLASS_NAME::_MoveUp(HeapLink* link) +{ + while (true) { + int parent = (link->fIndex - 1) / 2; + if (link->fIndex > 0 + && sCompare(link->fKey, sGetLink(fElements[parent])->fKey)) { + + sGetLink(fElements[parent])->fIndex = link->fIndex; + + Element* element = fElements[link->fIndex]; + fElements[link->fIndex] = fElements[parent]; + fElements[parent] = element; + + link->fIndex = parent; + } else + break; + } +} + + +HEAP_TEMPLATE_LIST +void +HEAP_CLASS_NAME::_MoveDown(HeapLink* link) +{ + int current; + + while (true) { + current = link->fIndex; + + int child = 2 * link->fIndex + 1; + if (child < fLastElement + && sCompare(sGetLink(fElements[child])->fKey, link->fKey)) { + current = child; + } + + child = 2 * link->fIndex + 2; + if (child < fLastElement + && sCompare(sGetLink(fElements[child])->fKey, + sGetLink(fElements[current])->fKey)) { + current = child; + } + + if (link->fIndex == current) + break; + + sGetLink(fElements[current])->fIndex = link->fIndex; + + Element* element = fElements[link->fIndex]; + fElements[link->fIndex] = fElements[current]; + fElements[current] = element; + + link->fIndex = current; + } +} + + +HEAP_TEMPLATE_LIST +Compare HEAP_CLASS_NAME::sCompare; + +HEAP_TEMPLATE_LIST +GetLink HEAP_CLASS_NAME::sGetLink; + + +#endif // KERNEL_UTIL_HEAP_H + diff --git a/headers/private/kernel/util/MinMaxHeap.h b/headers/private/kernel/util/MinMaxHeap.h new file mode 100644 index 0000000000..3eb47e260f --- /dev/null +++ b/headers/private/kernel/util/MinMaxHeap.h @@ -0,0 +1,503 @@ +/* + * Copyright 2013 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ +#ifndef KERNEL_UTIL_MIN_MAX_HEAP_H +#define KERNEL_UTIL_MIN_MAX_HEAP_H + + +#include + +#include + + +template +struct MinMaxHeapLink { + MinMaxHeapLink(); + + bool fMinTree; + int fIndex; + Key fKey; +}; + +template +class MinMaxHeapLinkImpl { +private: + typedef MinMaxHeapLink Link; + +public: + inline Link* GetMinMaxHeapLink(); + +private: + Link fMinMaxHeapLink; +}; + +template +class MinMaxHeapStandardGetLink { +private: + typedef MinMaxHeapLink Link; + +public: + inline Link* operator()(Element* element) const; +}; + +template Element::*LinkMember> +class MinMaxHeapMemberGetLink { +private: + typedef MinMaxHeapLink Link; + +public: + inline Link* operator()(Element* element) const; +}; + +template +class MinMaxHeapCompare { +public: + inline bool operator()(Key a, Key b); +}; + +#define MIN_MAX_HEAP_TEMPLATE_LIST \ + template +#define MIN_MAX_HEAP_CLASS_NAME MinMaxHeap + +template, + typename GetLink = MinMaxHeapStandardGetLink > +class MinMaxHeap { +public: + MinMaxHeap(); + MinMaxHeap(int initialSize); + ~MinMaxHeap(); + + inline Element* PeekMinimum() const; + inline Element* PeekMaximum() const; + + static const Key& GetKey(Element* element); + + inline void ModifyKey(Element* element, Key newKey); + + inline void RemoveMinimum(); + inline void RemoveMaximum(); + + inline status_t Insert(Element* element, Key key); + +private: + status_t _GrowHeap(int minimalSize = 0); + + void _MoveUp(MinMaxHeapLink* link); + void _MoveDown(MinMaxHeapLink* link); + bool _ChangeTree(MinMaxHeapLink* link); + + void _RemoveLast(bool minTree); + + Element** fMinElements; + int fMinLastElement; + + Element** fMaxElements; + int fMaxLastElement; + + int fSize; + + static Compare sCompare; + static GetLink sGetLink; +}; + + +#if KDEBUG +template +MinMaxHeapLink::MinMaxHeapLink() + : + fIndex(-1) +{ +} +#else +template +MinMaxHeapLink::MinMaxHeapLink() +{ +} +#endif + + +template +MinMaxHeapLink* +MinMaxHeapLinkImpl::GetMinMaxHeapLink() +{ + return &fMinMaxHeapLink; +} + + +template +MinMaxHeapLink* +MinMaxHeapStandardGetLink::operator()(Element* element) const +{ + return element->GetMinMaxHeapLink(); +} + + +template Element::*LinkMember> +MinMaxHeapLink* +MinMaxHeapMemberGetLink::operator()( + Element* element) const +{ + return &(element->*LinkMember); +} + + +template +bool +MinMaxHeapCompare::operator()(Key a, Key b) +{ + return a < b; +} + + +MIN_MAX_HEAP_TEMPLATE_LIST +MIN_MAX_HEAP_CLASS_NAME::MinMaxHeap() + : + fMinElements(NULL), + fMinLastElement(0), + fMaxElements(NULL), + fMaxLastElement(0), + fSize(0) +{ +} + + +MIN_MAX_HEAP_TEMPLATE_LIST +MIN_MAX_HEAP_CLASS_NAME::MinMaxHeap(int initialSize) + : + fMinElements(NULL), + fMinLastElement(0), + fMaxElements(NULL), + fMaxLastElement(0), + fSize(0) +{ + _GrowHeap(initialSize); +} + + +MIN_MAX_HEAP_TEMPLATE_LIST +MIN_MAX_HEAP_CLASS_NAME::~MinMaxHeap() +{ + free(fMinElements); +} + + +MIN_MAX_HEAP_TEMPLATE_LIST +Element* +MIN_MAX_HEAP_CLASS_NAME::PeekMinimum() const +{ + if (fMinLastElement > 0) + return fMinElements[0]; + else if (fMaxLastElement > 0) { + ASSERT(fMaxLastElement == 1); + return fMaxElements[0]; + } + + return NULL; +} + + +MIN_MAX_HEAP_TEMPLATE_LIST +Element* +MIN_MAX_HEAP_CLASS_NAME::PeekMaximum() const +{ + if (fMaxLastElement > 0) + return fMaxElements[0]; + else if (fMinLastElement > 0) { + ASSERT(fMinLastElement == 1); + return fMinElements[0]; + } + + return NULL; +} + + +MIN_MAX_HEAP_TEMPLATE_LIST +const Key& +MIN_MAX_HEAP_CLASS_NAME::GetKey(Element* element) +{ + return sGetLink(element)->fKey; +} + + +MIN_MAX_HEAP_TEMPLATE_LIST +void +MIN_MAX_HEAP_CLASS_NAME::ModifyKey(Element* element, Key newKey) +{ + MinMaxHeapLink* link = sGetLink(element); + + Key oldKey = link->fKey; + link->fKey = newKey; + + if (!sCompare(newKey, oldKey) && !sCompare(oldKey, newKey)) + return; + + if (sCompare(newKey, oldKey) ^ !link->fMinTree) + _MoveUp(link); + else + _MoveDown(link); +} + + +MIN_MAX_HEAP_TEMPLATE_LIST +void +MIN_MAX_HEAP_CLASS_NAME::RemoveMinimum() +{ + if (fMinLastElement == 0) { + ASSERT(fMaxLastElement == 1); + RemoveMaximum(); + return; + } + +#if KDEBUG + Element* element = PeekMinimum(); + MinMaxHeapLink* link = sGetLink(element); + ASSERT(link->fIndex != -1); + link->fIndex = -1; +#endif + + _RemoveLast(true); +} + + +MIN_MAX_HEAP_TEMPLATE_LIST +void +MIN_MAX_HEAP_CLASS_NAME::RemoveMaximum() +{ + if (fMaxLastElement == 0) { + ASSERT(fMinLastElement == 1); + RemoveMinimum(); + return; + } + +#if KDEBUG + Element* element = PeekMaximum(); + MinMaxHeapLink* link = sGetLink(element); + ASSERT(link->fIndex != -1); + link->fIndex = -1; +#endif + + _RemoveLast(false); +} + + +MIN_MAX_HEAP_TEMPLATE_LIST +status_t +MIN_MAX_HEAP_CLASS_NAME::Insert(Element* element, Key key) +{ + if (min_c(fMinLastElement, fMaxLastElement) == fSize) { + ASSERT(max_c(fMinLastElement, fMaxLastElement) == fSize); + status_t result = _GrowHeap(); + if (result != B_OK) + return result; + } + + ASSERT(fMinLastElement < fSize || fMaxLastElement < fSize); + + MinMaxHeapLink* link = sGetLink(element); + + ASSERT(link->fIndex == -1); + + link->fMinTree = fMinLastElement < fMaxLastElement; + + int& lastElement = link->fMinTree ? fMinLastElement : fMaxLastElement; + Element** tree = link->fMinTree ? fMinElements : fMaxElements; + + tree[lastElement] = element; + link->fIndex = lastElement++; + link->fKey = key; + + if (!_ChangeTree(link)) + _MoveUp(link); + + return B_OK; +} + + +MIN_MAX_HEAP_TEMPLATE_LIST +status_t +MIN_MAX_HEAP_CLASS_NAME::_GrowHeap(int minimalSize) +{ + minimalSize = minimalSize % 2 == 0 ? minimalSize : minimalSize + 1; + int newSize = max_c(max_c(fSize * 4, 4), minimalSize); + + size_t arraySize = newSize * sizeof(Element*); + Element** newBuffer + = reinterpret_cast(realloc(fMinElements, arraySize)); + if (newBuffer == NULL) + return B_NO_MEMORY; + fMinElements = newBuffer; + + newBuffer += newSize / 2; + if (fMaxLastElement > 0) + memcpy(newBuffer, fMinElements + fSize, fSize * sizeof(Element*)); + fMaxElements = newBuffer; + + fSize = newSize / 2; + return B_OK; +} + + +MIN_MAX_HEAP_TEMPLATE_LIST +void +MIN_MAX_HEAP_CLASS_NAME::_MoveUp(MinMaxHeapLink* link) +{ + Element** tree = link->fMinTree ? fMinElements : fMaxElements; + while (true) { + if (link->fIndex <= 0) + break; + + int parent = (link->fIndex - 1) / 2; + bool isSmaller = sCompare(link->fKey, sGetLink(tree[parent])->fKey); + if (isSmaller ^ !link->fMinTree) { + ASSERT(sGetLink(tree[parent])->fIndex == parent); + sGetLink(tree[parent])->fIndex = link->fIndex; + + Element* element = tree[link->fIndex]; + tree[link->fIndex] = tree[parent]; + tree[parent] = element; + + link->fIndex = parent; + } else + break; + } +} + + +MIN_MAX_HEAP_TEMPLATE_LIST +void +MIN_MAX_HEAP_CLASS_NAME::_MoveDown(MinMaxHeapLink* link) +{ + int current; + + int lastElement = link->fMinTree ? fMinLastElement : fMaxLastElement; + Element** tree = link->fMinTree ? fMinElements : fMaxElements; + while (true) { + current = link->fIndex; + + int child = 2 * link->fIndex + 1; + if (child < lastElement) { + bool isSmaller = sCompare(sGetLink(tree[child])->fKey, link->fKey); + if (isSmaller ^ !link->fMinTree) + current = child; + } + + child = 2 * link->fIndex + 2; + if (child < lastElement) { + bool isSmaller = sCompare(sGetLink(tree[child])->fKey, + sGetLink(tree[current])->fKey); + if (isSmaller ^ !link->fMinTree) + current = child; + } + + if (link->fIndex == current) + break; + + ASSERT(sGetLink(tree[current])->fIndex == current); + sGetLink(tree[current])->fIndex = link->fIndex; + + Element* element = tree[link->fIndex]; + tree[link->fIndex] = tree[current]; + tree[current] = element; + + link->fIndex = current; + } + + if (2 * link->fIndex + 1 >= lastElement) + _ChangeTree(link); +} + + +MIN_MAX_HEAP_TEMPLATE_LIST +bool +MIN_MAX_HEAP_CLASS_NAME::_ChangeTree(MinMaxHeapLink* link) +{ + int otherLastElement = link->fMinTree ? fMaxLastElement : fMinLastElement; + + Element** currentTree = link->fMinTree ? fMinElements : fMaxElements; + Element** otherTree = link->fMinTree ? fMaxElements : fMinElements; + + if (otherLastElement <= 0) { + ASSERT(link->fMinTree ? fMinLastElement : fMaxLastElement == 1); + return false; + } + + ASSERT((link->fIndex - 1) / 2 < otherLastElement); + + Element* predecessor; + if (2 * link->fIndex + 1 < otherLastElement) { + predecessor = otherTree[2 * link->fIndex + 1]; + ASSERT(sGetLink(predecessor)->fIndex == 2 * link->fIndex + 1); + } else if (link->fIndex < otherLastElement) { + predecessor = otherTree[link->fIndex]; + ASSERT(sGetLink(predecessor)->fIndex == link->fIndex); + } else { + predecessor = otherTree[(link->fIndex - 1) / 2]; + ASSERT(sGetLink(predecessor)->fIndex == (link->fIndex - 1) / 2); + } + MinMaxHeapLink* predecessorLink = sGetLink(predecessor); + + bool isSmaller = sCompare(predecessorLink->fKey, link->fKey); + if (isSmaller ^ !link->fMinTree) { + Element* element = currentTree[link->fIndex]; + currentTree[link->fIndex] = otherTree[predecessorLink->fIndex]; + otherTree[predecessorLink->fIndex] = element; + + int index = link->fIndex; + link->fIndex = predecessorLink->fIndex; + predecessorLink->fIndex = index; + + predecessorLink->fMinTree = !predecessorLink->fMinTree; + link->fMinTree = !link->fMinTree; + + _MoveUp(link); + return true; + } + + return false; +} + + +MIN_MAX_HEAP_TEMPLATE_LIST +void +MIN_MAX_HEAP_CLASS_NAME::_RemoveLast(bool minTree) +{ + bool deleteMin = fMaxLastElement < fMinLastElement; + + Element** tree = deleteMin ? fMinElements : fMaxElements; + int& lastElement = deleteMin ? fMinLastElement : fMaxLastElement; + + ASSERT(lastElement > 0); + lastElement--; + if (lastElement == 0 && deleteMin == minTree) + return; + + Element* element = tree[lastElement]; + + if (minTree) + fMinElements[0] = element; + else + fMaxElements[0] = element; + + MinMaxHeapLink* link = sGetLink(element); + link->fIndex = 0; + link->fMinTree = minTree; + _MoveDown(link); +} + + +MIN_MAX_HEAP_TEMPLATE_LIST +Compare MIN_MAX_HEAP_CLASS_NAME::sCompare; + +MIN_MAX_HEAP_TEMPLATE_LIST +GetLink MIN_MAX_HEAP_CLASS_NAME::sGetLink; + + +#endif // KERNEL_UTIL_MIN_MAX_HEAP_H + diff --git a/headers/private/kernel/util/atomic.h b/headers/private/kernel/util/atomic.h index 510df65bec..40b057c608 100644 --- a/headers/private/kernel/util/atomic.h +++ b/headers/private/kernel/util/atomic.h @@ -10,6 +10,8 @@ #include +#include + #ifdef __cplusplus @@ -18,22 +20,34 @@ atomic_pointer_test_and_set(PointerType** _pointer, const PointerType* set, const PointerType* test) { #if LONG_MAX == INT_MAX - return (PointerType*)atomic_test_and_set((vint32*)_pointer, (int32)set, + return (PointerType*)atomic_test_and_set((int32*)_pointer, (int32)set, (int32)test); #else - return (PointerType*)atomic_test_and_set64((vint64*)_pointer, (int64)set, + return (PointerType*)atomic_test_and_set64((int64*)_pointer, (int64)set, (int64)test); #endif } template PointerType* -atomic_pointer_set(PointerType** _pointer, const PointerType* set) +atomic_pointer_get_and_set(PointerType** _pointer, const PointerType* set) { #if LONG_MAX == INT_MAX - return (PointerType*)atomic_set((vint32*)_pointer, (int32)set); + return (PointerType*)atomic_get_and_set((int32*)_pointer, (int32)set); #else - return (PointerType*)atomic_set64((vint64*)_pointer, (int64)set); + return (PointerType*)atomic_get_and_set64((int64*)_pointer, (int64)set); +#endif +} + + +template void +atomic_pointer_set(PointerType** _pointer, const PointerType* set) +{ + ASSERT((addr_t(_pointer) & (sizeof(PointerType*) - 1)) == 0); +#if LONG_MAX == INT_MAX + atomic_set((int32*)_pointer, (int32)set); +#else + atomic_set64((int64*)_pointer, (int64)set); #endif } @@ -41,10 +55,11 @@ atomic_pointer_set(PointerType** _pointer, const PointerType* set) template PointerType* atomic_pointer_get(PointerType** _pointer) { + ASSERT((addr_t(_pointer) & (sizeof(PointerType*) - 1)) == 0); #if LONG_MAX == INT_MAX - return (PointerType*)atomic_get((vint32*)_pointer); + return (PointerType*)atomic_get((int32*)_pointer); #else - return (PointerType*)atomic_get64((vint64*)_pointer); + return (PointerType*)atomic_get64((int64*)_pointer); #endif } diff --git a/headers/private/kernel/vm/vm.h b/headers/private/kernel/vm/vm.h index 9aa7f2154a..ce85089594 100644 --- a/headers/private/kernel/vm/vm.h +++ b/headers/private/kernel/vm/vm.h @@ -142,7 +142,7 @@ status_t vm_get_physical_page_debug(phys_addr_t paddr, addr_t* vaddr, void** _handle); status_t vm_put_physical_page_debug(addr_t vaddr, void* handle); -void vm_get_info(struct system_memory_info *info); +void vm_get_info(system_info *info); uint32 vm_num_page_faults(void); off_t vm_available_memory(void); off_t vm_available_not_needed_memory(void); diff --git a/headers/private/kernel/vm/vm_types.h b/headers/private/kernel/vm/vm_types.h index 43c4f80cf8..85aa030687 100644 --- a/headers/private/kernel/vm/vm_types.h +++ b/headers/private/kernel/vm/vm_types.h @@ -136,7 +136,7 @@ public: #endif #if DEBUG_PAGE_ACCESS - vint32 accessing_thread; + int32 accessing_thread; #endif #if VM_PAGE_ALLOCATION_TRACKING_AVAILABLE diff --git a/headers/private/kernel/wait_for_objects.h b/headers/private/kernel/wait_for_objects.h index 8d1b0add5b..30cd6f7f0e 100644 --- a/headers/private/kernel/wait_for_objects.h +++ b/headers/private/kernel/wait_for_objects.h @@ -17,12 +17,12 @@ struct select_sync; typedef struct select_info { struct select_info* next; // next in the object's list struct select_sync* sync; - vint32 events; + int32 events; uint16 selected_events; } select_info; typedef struct select_sync { - vint32 ref_count; + int32 ref_count; sem_id sem; uint32 count; struct select_info* set; diff --git a/headers/private/libroot/pthread_private.h b/headers/private/libroot/pthread_private.h index 1ddc00c6be..659ac7b832 100644 --- a/headers/private/libroot/pthread_private.h +++ b/headers/private/libroot/pthread_private.h @@ -50,12 +50,12 @@ typedef struct _pthread_rwlockattr { typedef void (*pthread_key_destructor)(void *data); struct pthread_key { - vint32 sequence; + int32 sequence; pthread_key_destructor destructor; }; struct pthread_key_data { - vint32 sequence; + int32 sequence; void *value; }; diff --git a/headers/private/media/SharedBufferList.h b/headers/private/media/SharedBufferList.h index 37f8a7efb3..c5b93b131b 100644 --- a/headers/private/media/SharedBufferList.h +++ b/headers/private/media/SharedBufferList.h @@ -54,7 +54,7 @@ private: private: sem_id fSemaphore; - vint32 fAtom; + int32 fAtom; _shared_buffer_info fInfos[kMaxBuffers]; int32 fCount; diff --git a/headers/private/package/TempfileManager.h b/headers/private/package/TempfileManager.h index e53ebadaf6..3d118b278b 100644 --- a/headers/private/package/TempfileManager.h +++ b/headers/private/package/TempfileManager.h @@ -31,7 +31,7 @@ private: private: BDirectory fBaseDirectory; - vint32 fNextNumber; + int32 fNextNumber; }; diff --git a/headers/private/print/BeUtils.h b/headers/private/print/BeUtils.h index 3e1f25be79..a294c3bde4 100644 --- a/headers/private/print/BeUtils.h +++ b/headers/private/print/BeUtils.h @@ -53,7 +53,7 @@ status_t TestForAddonExistence(const char* name, directory_which which, // Reference counted object class Object { private: - volatile int32 fRefCount; + int32 fRefCount; public: // After construction reference count is 1 diff --git a/headers/private/shared/Referenceable.h b/headers/private/shared/Referenceable.h index ed9eff8663..0c7b2980df 100644 --- a/headers/private/shared/Referenceable.h +++ b/headers/private/shared/Referenceable.h @@ -30,7 +30,7 @@ protected: virtual void LastReferenceReleased(); protected: - vint32 fReferenceCount; + int32 fReferenceCount; }; diff --git a/headers/private/shared/WeakReferenceable.h b/headers/private/shared/WeakReferenceable.h index c09bb0c27d..7d1774fe32 100644 --- a/headers/private/shared/WeakReferenceable.h +++ b/headers/private/shared/WeakReferenceable.h @@ -30,7 +30,7 @@ public: void GetUnchecked(); private: - vint32 fUseCount; + int32 fUseCount; BWeakReferenceable* fObject; }; diff --git a/headers/private/shared/cpu_type.h b/headers/private/shared/cpu_type.h index 3317f95d44..bd0f91f1d2 100644 --- a/headers/private/shared/cpu_type.h +++ b/headers/private/shared/cpu_type.h @@ -1,5 +1,6 @@ /* * Copyright 2004-2013, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2013, Paweł Dziepak, pdziepak@quarnos.org. * Distributed under the terms of the MIT License. */ @@ -18,8 +19,9 @@ extern "C" { #endif -const char *get_cpu_vendor_string(enum cpu_types type); -const char *get_cpu_model_string(const system_info *info); +static const char* get_cpu_vendor_string(enum cpu_vendor cpuVendor); +static const char* get_cpu_model_string(enum cpu_platform platform, + enum cpu_vendor cpuVendor, uint32 cpuModel); void get_cpu_type(char *vendorBuffer, size_t vendorSize, char *modelBuffer, size_t modelSize); int32 get_rounded_cpu_speed(void); @@ -165,36 +167,16 @@ parse_amd(const char* name) #endif -const char * -get_cpu_vendor_string(enum cpu_types type) +static const char* +get_cpu_vendor_string(enum cpu_vendor cpuVendor) { -#if __POWERPC__ - /* We're not that nice here. */ - return "IBM/Motorola"; -#endif -#if defined(__INTEL__) || defined(__x86_64__) - /* Determine x86 vendor name */ - switch (type & B_CPU_x86_VENDOR_MASK) { - case B_CPU_INTEL_x86: - return "Intel"; - case B_CPU_AMD_x86: - return "AMD"; - case B_CPU_CYRIX_x86: - return "Cyrix"; - case B_CPU_IDT_x86: - /* IDT was bought by VIA */ - if (((type >> 8) & 0xf) >= 6) - return "VIA"; - return "IDT"; - case B_CPU_RISE_x86: - return "Rise"; - case B_CPU_TRANSMETA_x86: - return "Transmeta"; + static const char* vendorStrings[] = { + NULL, "AMD", "Cyrix", "IDT", "Intel", "Rise", "Transmeta", "VIA", + }; - default: - return NULL; - } -#endif + if ((size_t)cpuVendor >= sizeof(vendorStrings) / sizeof(const char*)) + return NULL; + return vendorStrings[cpuVendor]; } @@ -256,251 +238,222 @@ get_cpuid_model_string(char *name) #endif /* __INTEL__ || __x86_64__ */ -const char * -get_cpu_model_string(const system_info *info) +static const char* +get_cpu_model_string(enum cpu_platform platform, enum cpu_vendor cpuVendor, + uint32 cpuModel) { #if defined(__INTEL__) || defined(__x86_64__) char cpuidName[49]; - /* for use with get_cpuid_model_string() */ -#endif /* __INTEL__ || __x86_64__ */ +#endif + + (void)cpuVendor; + (void)cpuModel; - /* Determine CPU type */ - switch (info->cpu_type) { -#if __POWERPC__ - case B_CPU_PPC_603: - return "603"; - case B_CPU_PPC_603e: - return "603e"; - case B_CPU_PPC_750: - return "750"; - case B_CPU_PPC_604: - return "604"; - case B_CPU_PPC_604e: - return "604e"; - default: - return NULL; -#endif /* __POWERPC__ */ #if defined(__INTEL__) || defined(__x86_64__) - case B_CPU_x86: - return "Unknown x86"; + if (platform != B_CPU_x86 && platform != B_CPU_x86_64) + return NULL; - /* Intel */ - case B_CPU_INTEL_PENTIUM: - case B_CPU_INTEL_PENTIUM75: - return "Pentium"; - case B_CPU_INTEL_PENTIUM_486_OVERDRIVE: - case B_CPU_INTEL_PENTIUM75_486_OVERDRIVE: - return "Pentium OD"; - case B_CPU_INTEL_PENTIUM_MMX: - case B_CPU_INTEL_PENTIUM_MMX_MODEL_8: - return "Pentium MMX"; - case B_CPU_INTEL_PENTIUM_PRO: - return "Pentium Pro"; - case B_CPU_INTEL_PENTIUM_II_MODEL_3: - case B_CPU_INTEL_PENTIUM_II_MODEL_5: - return "Pentium II"; - case B_CPU_INTEL_CELERON: - case B_CPU_INTEL_CELERON_MODEL_22: - return "Celeron"; - case B_CPU_INTEL_PENTIUM_III: - case B_CPU_INTEL_PENTIUM_III_MODEL_8: - case B_CPU_INTEL_PENTIUM_III_MODEL_11: - case B_CPU_INTEL_PENTIUM_III_XEON: - return "Pentium III"; - case B_CPU_INTEL_PENTIUM_M: - case B_CPU_INTEL_PENTIUM_M_MODEL_13: - get_cpuid_model_string(cpuidName); - if (strcasestr(cpuidName, "Celeron") != NULL) - return "Pentium M Celeron"; - return "Pentium M"; - case B_CPU_INTEL_ATOM: - return "Atom"; - case B_CPU_INTEL_PENTIUM_CORE: - get_cpuid_model_string(cpuidName); - if (strcasestr(cpuidName, "Celeron") != NULL) - return "Core Celeron"; - return "Core"; - case B_CPU_INTEL_PENTIUM_CORE_2: - get_cpuid_model_string(cpuidName); - if (strcasestr(cpuidName, "Celeron") != NULL) - return "Core 2 Celeron"; - if (strcasestr(cpuidName, "Xeon") != NULL) - return "Core 2 Xeon"; - return "Core 2"; - case B_CPU_INTEL_PENTIUM_CORE_2_45_NM: - get_cpuid_model_string(cpuidName); - if (strcasestr(cpuidName, "Celeron") != NULL) - return "Core 2 Celeron"; - if (strcasestr(cpuidName, "Xeon") != NULL) - return "Core 2 Xeon"; - if (strcasestr(cpuidName, "Pentium") != NULL) - return "Pentium"; - if (strcasestr(cpuidName, "Extreme") != NULL) - return "Core 2 Extreme"; - return "Core 2"; - case B_CPU_INTEL_PENTIUM_CORE_I5_M430: - return "Core i5"; - case B_CPU_INTEL_PENTIUM_CORE_I7: - case B_CPU_INTEL_PENTIUM_CORE_I7_Q720: - get_cpuid_model_string(cpuidName); - if (strcasestr(cpuidName, "Xeon") != NULL) - return "Core i7 Xeon"; - return "Core i7"; - case B_CPU_INTEL_PENTIUM_IV: - case B_CPU_INTEL_PENTIUM_IV_MODEL_1: - case B_CPU_INTEL_PENTIUM_IV_MODEL_2: - case B_CPU_INTEL_PENTIUM_IV_MODEL_3: - case B_CPU_INTEL_PENTIUM_IV_MODEL_4: - get_cpuid_model_string(cpuidName); - if (strcasestr(cpuidName, "Celeron") != NULL) - return "Pentium 4 Celeron"; - if (strcasestr(cpuidName, "Xeon") != NULL) - return "Pentium 4 Xeon"; - return "Pentium 4"; + uint16 family = ((cpuModel >> 8) & 0xf) | ((cpuModel >> 16) & 0xff0); + uint16 model = ((cpuModel >> 4) & 0xf) | ((cpuModel >> 12) & 0xf0); + uint8 stepping = cpuModel & 0xf; - /* AMD */ - case B_CPU_AMD_K5_MODEL_0: - case B_CPU_AMD_K5_MODEL_1: - case B_CPU_AMD_K5_MODEL_2: - case B_CPU_AMD_K5_MODEL_3: - return "K5"; - case B_CPU_AMD_K6_MODEL_6: - case B_CPU_AMD_K6_MODEL_7: - return "K6"; - case B_CPU_AMD_K6_2: - return "K6-2"; - case B_CPU_AMD_K6_III: - case B_CPU_AMD_K6_III_MODEL_13: - return "K6-III"; - case B_CPU_AMD_GEODE_LX: - return "Geode LX"; - case B_CPU_AMD_ATHLON_MODEL_1: - case B_CPU_AMD_ATHLON_MODEL_2: - case B_CPU_AMD_ATHLON_THUNDERBIRD: - return "Athlon"; - case B_CPU_AMD_ATHLON_XP_MODEL_6: - case B_CPU_AMD_ATHLON_XP_MODEL_7: - case B_CPU_AMD_ATHLON_XP_MODEL_8: - case B_CPU_AMD_ATHLON_XP_MODEL_10: - return "Athlon XP"; - case B_CPU_AMD_DURON: - return "Duron"; - case B_CPU_AMD_SEMPRON_64_MODEL_28: - case B_CPU_AMD_SEMPRON_64_MODEL_44: - case B_CPU_AMD_SEMPRON_64_MODEL_127: - return "Sempron 64"; - case B_CPU_AMD_ATHLON_64_MODEL_3: - case B_CPU_AMD_ATHLON_64_MODEL_4: - case B_CPU_AMD_ATHLON_64_MODEL_7: - case B_CPU_AMD_ATHLON_64_MODEL_8: - case B_CPU_AMD_ATHLON_64_MODEL_11: - case B_CPU_AMD_ATHLON_64_MODEL_12: - case B_CPU_AMD_ATHLON_64_MODEL_14: - case B_CPU_AMD_ATHLON_64_MODEL_15: - case B_CPU_AMD_ATHLON_64_MODEL_20: - case B_CPU_AMD_ATHLON_64_MODEL_23: - case B_CPU_AMD_ATHLON_64_MODEL_24: - case B_CPU_AMD_ATHLON_64_MODEL_27: - case B_CPU_AMD_ATHLON_64_MODEL_31: - case B_CPU_AMD_ATHLON_64_MODEL_35: - case B_CPU_AMD_ATHLON_64_MODEL_43: - case B_CPU_AMD_ATHLON_64_MODEL_47: - case B_CPU_AMD_ATHLON_64_MODEL_63: - case B_CPU_AMD_ATHLON_64_MODEL_79: - case B_CPU_AMD_ATHLON_64_MODEL_95: - return "Athlon 64"; - case B_CPU_AMD_OPTERON_MODEL_5: - case B_CPU_AMD_OPTERON_MODEL_21: - case B_CPU_AMD_OPTERON_MODEL_33: - case B_CPU_AMD_OPTERON_MODEL_37: - case B_CPU_AMD_OPTERON_MODEL_39: - return "Opteron"; - case B_CPU_AMD_TURION_64_MODEL_36: - case B_CPU_AMD_TURION_64_MODEL_76: - case B_CPU_AMD_TURION_64_MODEL_104: - return "Turion 64"; - case B_CPU_AMD_PHENOM_MODEL_2: - return "Phenom"; - case B_CPU_AMD_PHENOM_II_MODEL_4: - case B_CPU_AMD_PHENOM_II_MODEL_5: - case B_CPU_AMD_PHENOM_II_MODEL_6: - case B_CPU_AMD_PHENOM_II_MODEL_10: - get_cpuid_model_string(cpuidName); - if (strcasestr(cpuidName, "Athlon") != NULL) - return "Athlon II"; - return "Phenom II"; - case B_CPU_AMD_A_SERIES_MODEL_1: - case B_CPU_AMD_A_SERIES_MODEL_16: - case B_CPU_AMD_A_SERIES_MODEL_19: + if (cpuVendor == B_CPU_VENDOR_AMD) { + if (family == 5) { + if (model <= 3) + return "K5"; + if (model <= 7) + return "K6"; + if (model == 8) + return "K6-2"; + if (model == 9 || model == 0xd) + return "K6-III"; + if (model == 0xa) + return "Geode LX"; + } else if (family == 6) { + if (model <= 2 || model == 4) + return "Athlon"; + if (model == 3) + return "Duron"; + if (model <= 8 || model == 0xa) + return "Athlon XP"; + } else if (family == 0xf) { + if (model <= 4 || model == 7 || model == 8 + || (model >= 0xb && model <= 0xf) || model == 0x14 + || model == 0x18 || model == 0x1b || model == 0x1f + || model == 0x23 || model == 0x2b + || ((model & 0xf) == 0xf && model >= 0x2f && model <= 0x7e)) { + return "Athlon 64"; + } + if (model == 5 || model == 0x15 || model == 0x21 || model == 0x25 + || model == 0x27) { + return "Opteron"; + } + if (model == 0x1c || model == 0x2c || model == 0x7f) + return "Sempron 64"; + if (model == 0x24 || model == 0x4c || model == 0x68) + return "Turion 64"; + } else if (family == 0x1f) { + if (model == 2) + return "Phenom"; + if ((model >= 4 && model <= 6) || model == 0xa) { + get_cpuid_model_string(cpuidName); + if (strcasestr(cpuidName, "Athlon") != NULL) + return "Athlon II"; + return "Phenom II"; + } + } else if (family == 0x3f) return "A-Series"; - case B_CPU_AMD_C_SERIES: - return "C-Series"; - case B_CPU_AMD_E_SERIES: - return "E-Series"; - case B_CPU_AMD_FX_SERIES_MODEL_1: - case B_CPU_AMD_FX_SERIES_MODEL_2: - return "FX-Series"; + else if (family == 0x5f) { + if (model == 1) + return "C-Series"; + if (model == 2) + return "E-Series"; + } else if (family == 0x6f) { + if (model == 1 || model == 2) + return "FX-Series"; + if (model == 0x10 || model == 0x13) + return "A-Series"; + } - /* Transmeta */ - case B_CPU_TRANSMETA_CRUSOE: - return "Crusoe"; - case B_CPU_TRANSMETA_EFFICEON: - case B_CPU_TRANSMETA_EFFICEON_2: - return "Efficeon"; - - /* IDT/VIA */ - case B_CPU_IDT_WINCHIP_C6: - return "WinChip C6"; - case B_CPU_IDT_WINCHIP_2: - return "WinChip 2"; - case B_CPU_VIA_C3_SAMUEL: - return "C3 Samuel"; - case B_CPU_VIA_C3_SAMUEL_2: - /* stepping identified the model */ - if ((info->cpu_revision & 0xf) < 8) - return "C3 Eden/Samuel 2"; - return "C3 Ezra"; - case B_CPU_VIA_C3_EZRA_T: - return "C3 Ezra-T"; - case B_CPU_VIA_C3_NEHEMIAH: - /* stepping identified the model */ - if ((info->cpu_revision & 0xf) < 8) - return "C3 Nehemiah"; - return "C3 Eden-N"; - case B_CPU_VIA_C7_ESTHER: - case B_CPU_VIA_C7_ESTHER_2: - return "C7"; - case B_CPU_VIA_NANO_ISAIAH: - return "Nano"; - - /* Cyrix/VIA */ - case B_CPU_CYRIX_GXm: - return "GXm"; - case B_CPU_CYRIX_6x86MX: - return "6x86MX"; - - /* Rise */ - case B_CPU_RISE_mP6: - return "mP6"; - - /* National Semiconductor */ - case B_CPU_NATIONAL_GEODE_GX1: - return "Geode GX1"; - - default: - if ((info->cpu_type & B_CPU_x86_VENDOR_MASK) == B_CPU_INTEL_x86) { - // Fallback to manual parsing of the model string - get_cpuid_model_string(cpuidName); - return parse_intel(cpuidName); - } - if ((info->cpu_type & B_CPU_x86_VENDOR_MASK) == B_CPU_AMD_x86) { - // Fallback to manual parsing of the model string - get_cpuid_model_string(cpuidName); - return parse_amd(cpuidName); - } - return NULL; -#endif /* __INTEL__ || __x86_64__ */ + // Fallback to manual parsing of the model string + get_cpuid_model_string(cpuidName); + return parse_amd(cpuidName); } + + if (cpuVendor == B_CPU_VENDOR_CYRIX) { + if (family == 5 && model == 4) + return "GXm"; + if (family == 6) + return "6x86MX"; + return NULL; + } + + if (cpuVendor == B_CPU_VENDOR_INTEL) { + if (family == 5) { + if (model == 1 || model == 2) + return "Pentium"; + if (model == 3 || model == 9) + return "Pentium OD"; + if (model == 4 || model == 8) + return "Pentium MMX"; + } else if (family == 6) { + if (model == 1) + return "Pentium Pro"; + if (model == 3 || model == 5) + return "Pentium II"; + if (model == 6) + return "Celeron"; + if (model == 7 || model == 8 || model == 0xa || model == 0xb) + return "Pentium III"; + if (model == 9 || model == 0xd) { + get_cpuid_model_string(cpuidName); + if (strcasestr(cpuidName, "Celeron") != NULL) + return "Pentium M Celeron"; + return "Pentium M"; + } + if (model == 0x1c || model == 0x26 || model == 0x36) + return "Atom"; + if (model == 0xe) { + get_cpuid_model_string(cpuidName); + if (strcasestr(cpuidName, "Celeron") != NULL) + return "Core Celeron"; + return "Core"; + } + if (model == 0xf || model == 0x17) { + get_cpuid_model_string(cpuidName); + if (strcasestr(cpuidName, "Celeron") != NULL) + return "Core 2 Celeron"; + if (strcasestr(cpuidName, "Xeon") != NULL) + return "Core 2 Xeon"; + if (strcasestr(cpuidName, "Pentium") != NULL) + return "Pentium"; + if (strcasestr(cpuidName, "Extreme") != NULL) + return "Core 2 Extreme"; + return "Core 2"; + } + if (model == 0x25) + return "Core i5"; + if (model == 0x1a || model == 0x1e) { + get_cpuid_model_string(cpuidName); + if (strcasestr(cpuidName, "Xeon") != NULL) + return "Core i7 Xeon"; + return "Core i7"; + } + } else if (family == 0xf) { + if (model <= 4) { + get_cpuid_model_string(cpuidName); + if (strcasestr(cpuidName, "Celeron") != NULL) + return "Pentium 4 Celeron"; + if (strcasestr(cpuidName, "Xeon") != NULL) + return "Pentium 4 Xeon"; + return "Pentium 4"; + } + } + + // Fallback to manual parsing of the model string + get_cpuid_model_string(cpuidName); + return parse_intel(cpuidName); + } + + if (cpuVendor == B_CPU_VENDOR_NATIONAL_SEMICONDUCTOR) { + if (family == 5) { + if (model == 4) + return "Geode GX1"; + if (model == 5) + return "Geode GX2"; + return NULL; + } + } + + if (cpuVendor == B_CPU_VENDOR_RISE) { + if (family == 5) + return "mP6"; + return NULL; + } + + if (cpuVendor == B_CPU_VENDOR_TRANSMETA) { + if (family == 5 && model == 4) + return "Crusoe"; + if (family == 0xf && (model == 2 || model == 3)) + return "Efficeon"; + return NULL; + } + + if (cpuVendor == B_CPU_VENDOR_VIA) { + if (family == 5) { + if (model == 4) + return "WinChip C6"; + if (model == 8) + return "WinChip 2"; + if (model == 9) + return "WinChip 3"; + return NULL; + } else if (family == 6) { + if (model == 6) + return "C3 Samuel"; + if (model == 7) { + if (stepping < 8) + return "C3 Eden/Samuel 2"; + return "C3 Ezra"; + } + if (model == 8) + return "C3 Ezra-T"; + if (model == 9) { + if (stepping < 8) + return "C3 Nehemiah"; + return "C3 Ezra-N"; + } + if (model == 0xa || model == 0xd) + return "C7"; + if (model == 0xf) + return "Nano"; + return NULL; + } + } + +#endif + + return NULL; } @@ -509,15 +462,42 @@ get_cpu_type(char *vendorBuffer, size_t vendorSize, char *modelBuffer, size_t modelSize) { const char *vendor, *model; - system_info info; - get_system_info(&info); + uint32 topologyNodeCount = 0; + cpu_topology_node_info* topology = NULL; + get_cpu_topology_info(NULL, &topologyNodeCount); + if (topologyNodeCount != 0) + topology = new cpu_topology_node_info[topologyNodeCount]; + get_cpu_topology_info(topology, &topologyNodeCount); - vendor = get_cpu_vendor_string(info.cpu_type); + enum cpu_platform platform = B_CPU_UNKNOWN; + enum cpu_vendor cpuVendor = B_CPU_VENDOR_UNKNOWN; + uint32 cpuModel = 0; + for (uint32 i = 0; i < topologyNodeCount; i++) { + switch (topology[i].type) { + case B_TOPOLOGY_ROOT: + platform = topology[i].data.root.platform; + break; + + case B_TOPOLOGY_PACKAGE: + cpuVendor = topology[i].data.package.vendor; + break; + + case B_TOPOLOGY_CORE: + cpuModel = topology[i].data.core.model; + break; + + default: + break; + } + } + delete[] topology; + + vendor = get_cpu_vendor_string(cpuVendor); if (vendor == NULL) vendor = "Unknown"; - model = get_cpu_model_string(&info); + model = get_cpu_model_string(platform, cpuVendor, cpuModel); if (model == NULL) model = "Unknown"; @@ -536,14 +516,27 @@ get_cpu_type(char *vendorBuffer, size_t vendorSize, char *modelBuffer, int32 get_rounded_cpu_speed(void) { - system_info info; + uint32 topologyNodeCount = 0; + cpu_topology_node_info* topology = NULL; + get_cpu_topology_info(NULL, &topologyNodeCount); + if (topologyNodeCount != 0) + topology = new cpu_topology_node_info[topologyNodeCount]; + get_cpu_topology_info(topology, &topologyNodeCount); + + uint64 cpuFrequency = 0; + for (uint32 i = 0; i < topologyNodeCount; i++) { + if (topology[i].type == B_TOPOLOGY_CORE) { + cpuFrequency = topology[i].data.core.default_frequency; + break; + } + } + delete[] topology; int target, frac, delta; int freqs[] = { 100, 50, 25, 75, 33, 67, 20, 40, 60, 80, 10, 30, 70, 90 }; uint x; - get_system_info(&info); - target = info.cpu_clock_speed / 1000000; + target = cpuFrequency / 1000000; frac = target % 100; delta = -frac; diff --git a/headers/private/shared/locks.h b/headers/private/shared/locks.h index 052f24b6ec..27da7fc212 100644 --- a/headers/private/shared/locks.h +++ b/headers/private/shared/locks.h @@ -18,6 +18,7 @@ typedef struct mutex { } mutex; #define MUTEX_FLAG_CLONE_NAME 0x1 +#define MUTEX_FLAG_ADAPTIVE 0x2 #define MUTEX_INITIALIZER(name) { name, 0, 0 } void mutex_init(mutex *lock, const char *name); @@ -71,7 +72,7 @@ int32 recursive_lock_get_recursion(recursive_lock *lock); #define INIT_ONCE_UNINITIALIZED -1 #define INIT_ONCE_INITIALIZED -4 -status_t __init_once(vint32* control, status_t (*initRoutine)(void*), +status_t __init_once(int32* control, status_t (*initRoutine)(void*), void* data); #ifdef __cplusplus diff --git a/headers/private/support/StringPrivate.h b/headers/private/support/StringPrivate.h index 799151b66a..0ad274c8c4 100644 --- a/headers/private/support/StringPrivate.h +++ b/headers/private/support/StringPrivate.h @@ -32,12 +32,12 @@ public: return fString._IsShareable(); } - static vint32& DataRefCount(char* data) + static int32& DataRefCount(char* data) { return *(((int32 *)data) - 2); } - vint32& DataRefCount() + int32& DataRefCount() { return DataRefCount(Data()); } diff --git a/headers/private/system/syscalls.h b/headers/private/system/syscalls.h index 438a3ea310..3f475e7886 100644 --- a/headers/private/system/syscalls.h +++ b/headers/private/system/syscalls.h @@ -192,6 +192,9 @@ extern status_t _kern_unblock_threads(thread_id* threads, uint32 count, extern bigtime_t _kern_estimate_max_scheduling_latency(thread_id thread); +extern status_t _kern_set_scheduler_mode(int32 mode); +extern int32 _kern_get_scheduler_mode(void); + // user/group functions extern gid_t _kern_getgid(bool effective); extern uid_t _kern_getuid(bool effective); @@ -511,9 +514,13 @@ extern int64 _kern_atomic_get64(vint64 *value); #endif // ATOMIC64_FUNCS_ARE_SYSCALLS /* System informations */ -extern status_t _kern_get_system_info(system_info *info, size_t size); -extern status_t _kern_get_system_info_etc(int32 id, void *buffer, - size_t bufferSize); +extern status_t _kern_get_system_info(system_info* info); +extern status_t _kern_get_cpu_info(uint32 firstCPU, uint32 cpuCount, + cpu_info* info); +extern status_t _kern_get_cpu_topology_info( + cpu_topology_node_info* topologyInfos, + uint32* topologyInfoCount); + extern status_t _kern_analyze_scheduling(bigtime_t from, bigtime_t until, void* buffer, size_t size, struct scheduling_analysis* analysis); diff --git a/headers/private/system/system_info.h b/headers/private/system/system_info.h index 888c4423c8..e04dd61f26 100644 --- a/headers/private/system/system_info.h +++ b/headers/private/system/system_info.h @@ -9,21 +9,6 @@ #include -#define B_MEMORY_INFO 'memo' - -struct system_memory_info { - uint64 max_memory; - uint64 free_memory; - uint64 needed_memory; - uint64 max_swap_space; - uint64 free_swap_space; - uint64 block_cache_memory; - uint32 page_faults; - - // TODO: add active/inactive page counts, swap in/out, ... -}; - - enum { // team creation or deletion; object == -1; either one also triggers on // exec() @@ -63,7 +48,10 @@ extern "C" { #endif -status_t __get_system_info_etc(int32 id, void* buffer, size_t bufferSize); +status_t __get_system_info(system_info* info); +status_t __get_cpu_info(uint32 firstCPU, uint32 cpuCount, cpu_info* info); +status_t __get_cpu_topology_info(cpu_topology_node_info* topologyInfos, + uint32* topologyInfoCount); status_t __start_watching_system(int32 object, uint32 flags, port_id port, int32 token); diff --git a/src/add-ons/kernel/Jamfile b/src/add-ons/kernel/Jamfile index 5a5b275cb3..a58d6382b9 100644 --- a/src/add-ons/kernel/Jamfile +++ b/src/add-ons/kernel/Jamfile @@ -14,3 +14,4 @@ SubInclude HAIKU_TOP src add-ons kernel media ; SubInclude HAIKU_TOP src add-ons kernel partitioning_systems ; SubInclude HAIKU_TOP src add-ons kernel generic ; SubInclude HAIKU_TOP src add-ons kernel bluetooth ; +SubInclude HAIKU_TOP src add-ons kernel power ; diff --git a/src/add-ons/kernel/bus_managers/acpi/ACPICAHaiku.cpp b/src/add-ons/kernel/bus_managers/acpi/ACPICAHaiku.cpp index d001e0e2be..68af7542ac 100644 --- a/src/add-ons/kernel/bus_managers/acpi/ACPICAHaiku.cpp +++ b/src/add-ons/kernel/bus_managers/acpi/ACPICAHaiku.cpp @@ -676,7 +676,7 @@ AcpiOsCreateLock(ACPI_SPINLOCK *outHandle) if (*outHandle == NULL) return AE_NO_MEMORY; - **outHandle = B_SPINLOCK_INITIALIZER; + B_INITIALIZE_SPINLOCK(*outHandle); return AE_OK; } diff --git a/src/add-ons/kernel/bus_managers/acpi/EmbeddedController.h b/src/add-ons/kernel/bus_managers/acpi/EmbeddedController.h index 2630bbf52a..38488c9a86 100644 --- a/src/add-ons/kernel/bus_managers/acpi/EmbeddedController.h +++ b/src/add-ons/kernel/bus_managers/acpi/EmbeddedController.h @@ -151,7 +151,7 @@ struct acpi_ec_cookie { mutex ec_lock; int ec_burstactive; int ec_sci_pending; - vint32 ec_gencount; + int32 ec_gencount; ConditionVariable ec_condition_var; int ec_suspending; }; diff --git a/src/add-ons/kernel/bus_managers/firewire/timer.cpp b/src/add-ons/kernel/bus_managers/firewire/timer.cpp index 7299d9037b..4df8780784 100644 --- a/src/add-ons/kernel/bus_managers/firewire/timer.cpp +++ b/src/add-ons/kernel/bus_managers/firewire/timer.cpp @@ -188,7 +188,7 @@ initialize_timer(void) { sTimerCount = 0; sTimerNextId = 1; - sTimerSpinlock = 0; + B_INITIALIZE_SPINLOCK(&sTimerSpinlock); sTimerThread = spawn_kernel_thread(timer_thread, "firewire timer", 80, 0); sTimerSem = create_sem(0, "firewire timer"); diff --git a/src/add-ons/kernel/bus_managers/ps2/ps2_dev.h b/src/add-ons/kernel/bus_managers/ps2/ps2_dev.h index 229dbe0c0f..98c8c45cdb 100644 --- a/src/add-ons/kernel/bus_managers/ps2/ps2_dev.h +++ b/src/add-ons/kernel/bus_managers/ps2/ps2_dev.h @@ -28,7 +28,7 @@ struct ps2_dev { bool active; uint8 idx; sem_id result_sem; - vint32 flags; + int32 flags; uint8 * result_buf; int result_buf_idx; int result_buf_cnt; diff --git a/src/add-ons/kernel/bus_managers/random/yarrow_rng.cpp b/src/add-ons/kernel/bus_managers/random/yarrow_rng.cpp index bab1123d12..48e70fdd8f 100644 --- a/src/add-ons/kernel/bus_managers/random/yarrow_rng.cpp +++ b/src/add-ons/kernel/bus_managers/random/yarrow_rng.cpp @@ -158,7 +158,7 @@ reseed(ch_randgen *prandgen, const uint32 initTimes) // random seed on startup by reading from /dev/urandom, perl // programs are all but unusable when at least one other thread // hogs the CPU. - thread_yield(false); + thread_yield(); // TODO: Introduce a clock_counter() function that directly returns // the value of the hardware clock counter. This will be cheaper diff --git a/src/add-ons/kernel/cpu/x86/amd.cpp b/src/add-ons/kernel/cpu/x86/amd.cpp index 5d95c01c9a..d3fd31aaad 100644 --- a/src/add-ons/kernel/cpu/x86/amd.cpp +++ b/src/add-ons/kernel/cpu/x86/amd.cpp @@ -10,7 +10,7 @@ #include "amd.h" #include "generic_x86.h" -#include +#include static void @@ -23,16 +23,12 @@ amd_init_mtrrs(void) static status_t amd_init(void) { - system_info info; - if (get_system_info(&info) != B_OK) - return B_ERROR; - - if ((info.cpu_type & B_CPU_x86_VENDOR_MASK) != B_CPU_AMD_x86) + if (gCPU[0].arch.vendor != VENDOR_AMD) return B_ERROR; // The K6-2 doesn't seem to support write-combining (before model 9), // so we ignore anything before that one. - if (info.cpu_type <= B_CPU_AMD_K6_2) + if (gCPU[0].arch.family <= 5 || gCPU[0].arch.model < 9) return B_ERROR; generic_mtrr_compute_physical_mask(); diff --git a/src/add-ons/kernel/cpu/x86/generic_x86.cpp b/src/add-ons/kernel/cpu/x86/generic_x86.cpp index b394ff9b66..94e6a1b853 100644 --- a/src/add-ons/kernel/cpu/x86/generic_x86.cpp +++ b/src/add-ons/kernel/cpu/x86/generic_x86.cpp @@ -208,9 +208,9 @@ generic_mtrr_compute_physical_mask(void) uint32 bits = 36; cpuid_info cpuInfo; - if (get_current_cpuid(&cpuInfo, 0x80000000) == B_OK + if (get_current_cpuid(&cpuInfo, 0x80000000, 0) == B_OK && (cpuInfo.eax_0.max_eax & 0xff) >= 8) { - get_current_cpuid(&cpuInfo, 0x80000008); + get_current_cpuid(&cpuInfo, 0x80000008, 0); bits = cpuInfo.regs.eax & 0xff; // Obviously, the bits are not always reported correctly diff --git a/src/add-ons/kernel/cpu/x86/intel.cpp b/src/add-ons/kernel/cpu/x86/intel.cpp index a6935eb0ed..1bb9e72d53 100644 --- a/src/add-ons/kernel/cpu/x86/intel.cpp +++ b/src/add-ons/kernel/cpu/x86/intel.cpp @@ -10,7 +10,7 @@ #include "intel.h" #include "generic_x86.h" -#include +#include static void @@ -23,11 +23,7 @@ intel_init_mtrrs(void) static status_t intel_init(void) { - system_info info; - if (get_system_info(&info) != B_OK) - return B_ERROR; - - if ((info.cpu_type & B_CPU_x86_VENDOR_MASK) != B_CPU_INTEL_x86) + if (gCPU[0].arch.vendor != VENDOR_INTEL) return B_ERROR; generic_mtrr_compute_physical_mask(); diff --git a/src/add-ons/kernel/cpu/x86/via.cpp b/src/add-ons/kernel/cpu/x86/via.cpp index 6a222ff24d..4924886156 100644 --- a/src/add-ons/kernel/cpu/x86/via.cpp +++ b/src/add-ons/kernel/cpu/x86/via.cpp @@ -10,7 +10,7 @@ #include "via.h" #include "generic_x86.h" -#include +#include static uint32 @@ -41,11 +41,7 @@ via_set_mtrrs(uint8 defaultType, const x86_mtrr_info* infos, uint32 count) static status_t via_init(void) { - system_info info; - if (get_system_info(&info) != B_OK) - return B_ERROR; - - if ((info.cpu_type & B_CPU_x86_VENDOR_MASK) != B_CPU_VIA_IDT_x86) + if (gCPU[0].arch.vendor != VENDOR_CENTAUR) return B_ERROR; // current VIA CPUs have always 36 bit (or less?) diff --git a/src/add-ons/kernel/debugger/invalidate_on_exit/invalidate_on_exit.cpp b/src/add-ons/kernel/debugger/invalidate_on_exit/invalidate_on_exit.cpp index 3ff72b3842..abcea1c286 100644 --- a/src/add-ons/kernel/debugger/invalidate_on_exit/invalidate_on_exit.cpp +++ b/src/add-ons/kernel/debugger/invalidate_on_exit/invalidate_on_exit.cpp @@ -39,12 +39,6 @@ invalidate_loop(void *data) static void exit_debugger() { - // If someone holds the scheduler lock at this point, release_sem_etc() - // will block forever. So avoid that. - if (!try_acquire_spinlock(&gSchedulerLock)) - return; - release_spinlock(&gSchedulerLock); - release_sem_etc(sRequestSem, 1, B_DO_NOT_RESCHEDULE); } diff --git a/src/add-ons/kernel/drivers/audio/ac97/sis7018/Device.cpp b/src/add-ons/kernel/drivers/audio/ac97/sis7018/Device.cpp index e432ec88b2..80c1ab4fad 100644 --- a/src/add-ons/kernel/drivers/audio/ac97/sis7018/Device.cpp +++ b/src/add-ons/kernel/drivers/audio/ac97/sis7018/Device.cpp @@ -22,13 +22,14 @@ Device::Device(Device::Info &DeviceInfo, pci_info &PCIInfo) fPCIInfo(PCIInfo), fInfo(DeviceInfo), fIOBase(0), - fHWSpinlock(0), fInterruptsNest(0), fBuffersReadySem(-1), fMixer(this), fPlaybackStream(this, false), fRecordStream(this, true) { + B_INITIALIZE_SPINLOCK(&fHWSpinlock); + fStatus = _ReserveDeviceOnBus(true); if (fStatus != B_OK) return; // InitCheck will handle the rest diff --git a/src/add-ons/kernel/drivers/audio/ac97/sis7018/Device.h b/src/add-ons/kernel/drivers/audio/ac97/sis7018/Device.h index 399161a33d..974d781d0a 100644 --- a/src/add-ons/kernel/drivers/audio/ac97/sis7018/Device.h +++ b/src/add-ons/kernel/drivers/audio/ac97/sis7018/Device.h @@ -88,7 +88,7 @@ private: pci_info fPCIInfo; Info& fInfo; int fIOBase; - int32 fHWSpinlock; + spinlock fHWSpinlock; int32 fInterruptsNest; sem_id fBuffersReadySem; diff --git a/src/add-ons/kernel/drivers/audio/hda/device.cpp b/src/add-ons/kernel/drivers/audio/hda/device.cpp index aeb09966eb..f114f0ffc7 100644 --- a/src/add-ons/kernel/drivers/audio/hda/device.cpp +++ b/src/add-ons/kernel/drivers/audio/hda/device.cpp @@ -25,7 +25,7 @@ hda_open(const char* name, uint32 flags, void** cookie) if (controller == NULL) return ENODEV; - if (controller->opened != 0) + if (atomic_get(&controller->opened) != 0) return B_BUSY; status_t status = hda_hw_init(controller); diff --git a/src/add-ons/kernel/drivers/audio/hda/driver.h b/src/add-ons/kernel/drivers/audio/hda/driver.h index fc848b2cb1..18c06b0a04 100644 --- a/src/add-ons/kernel/drivers/audio/hda/driver.h +++ b/src/add-ons/kernel/drivers/audio/hda/driver.h @@ -65,7 +65,7 @@ struct hda_multi; */ struct hda_controller { struct pci_info pci_info; - vint32 opened; + int32 opened; const char* devfs_path; area_id regs_area; diff --git a/src/add-ons/kernel/drivers/audio/ice1712/util.c b/src/add-ons/kernel/drivers/audio/ice1712/util.c index c036e73fec..2feea676aa 100644 --- a/src/add-ons/kernel/drivers/audio/ice1712/util.c +++ b/src/add-ons/kernel/drivers/audio/ice1712/util.c @@ -16,7 +16,7 @@ #include "debug.h" #include "util.h" -spinlock slock = 0; +spinlock slock = B_SPINLOCK_INITIALIZER; uint32 round_to_pagesize(uint32 size); diff --git a/src/add-ons/kernel/drivers/disk/floppy/pc_floppy/floppy.c b/src/add-ons/kernel/drivers/disk/floppy/pc_floppy/floppy.c index e2f4ed7263..b78cda248d 100644 --- a/src/add-ons/kernel/drivers/disk/floppy/pc_floppy/floppy.c +++ b/src/add-ons/kernel/drivers/disk/floppy/pc_floppy/floppy.c @@ -222,7 +222,7 @@ init_driver(void) B_FULL_LOCK, B_READ_AREA|B_WRITE_AREA); if (master->buffer_area < B_OK) goto config_error2; - master->slock = 0; + B_INITIALIZE_SPINLOCK(&master->slock); master->isa = isa; if (install_io_interrupt_handler(master->irq, flo_intr, (void *)master, 0) < B_OK) goto config_error2; diff --git a/src/add-ons/kernel/drivers/graphics/common/Jamfile b/src/add-ons/kernel/drivers/graphics/common/Jamfile index 7ea40920b7..6fb4bde749 100644 --- a/src/add-ons/kernel/drivers/graphics/common/Jamfile +++ b/src/add-ons/kernel/drivers/graphics/common/Jamfile @@ -9,7 +9,5 @@ UsePrivateHeaders [ FDirName graphics radeon ] ; UsePrivateHeaders [ FDirName graphics common ] ; StaticLibrary libgraphicscommon.a : - log_coll.c - log_dump.c memory_manager.c ; diff --git a/src/add-ons/kernel/drivers/graphics/common/log_coll.c b/src/add-ons/kernel/drivers/graphics/common/log_coll.c deleted file mode 100644 index f9dec1e79f..0000000000 --- a/src/add-ons/kernel/drivers/graphics/common/log_coll.c +++ /dev/null @@ -1,129 +0,0 @@ -/* - Copyright (c) 2002, Thomas Kurschel - - Part of Radeon driver - - Both kernel and user space part. - (init and clean-up must be done in - kernel space). -*/ - - -#include "log_coll.h" - -#include -#include - -#include -#include -#include - -typedef struct log_info_t { - char *log_buffer; - uint32 log_buffer_len; - uint32 log_buffer_pos; - area_id area; -} log_info; - -#ifdef ENABLE_LOGGING - - -// write one log entry -void log( log_info *li, uint16 what, const uint8 num_args, ... ) -{ - uint32 pos; - va_list vl; - log_entry *entry; - uint32 i; - uint32 entry_size; - - entry_size = sizeof( log_entry ) + (num_args - 1) * sizeof( uint32 ); - pos = atomic_add( &li->log_buffer_pos, entry_size ); - - if( li->log_buffer_pos > li->log_buffer_len ) { - atomic_add( &li->log_buffer_pos, -entry_size ); - return; - } - - entry = (log_entry *)&li->log_buffer[pos]; - - entry->tsc = system_time(); - entry->what = what; - entry->num_args = num_args; - - va_start( vl, num_args ); - for( i = 0; i < num_args; ++i ) { - entry->args[i] = va_arg( vl, uint32 ); - } - va_end( vl ); -} - -#ifdef LOG_INCLUDE_STARTUP - -// create log buffer -log_info *log_init( uint32 size ) -{ - log_info *li; - area_id area; - - // buffer must be accessible from user mem - // to allow logging from there as well; - // you cannot clone this area as there are - // pointers which would break (it wouldn't be - // hard to get rid of them, but I don't care - // and keep it as simple as possible) - area = create_area( "fast_logger", - (void **)&li, B_ANY_KERNEL_ADDRESS, - (sizeof( log_info ) + size + (B_PAGE_SIZE - 1)) & ~(B_PAGE_SIZE - 1), - B_FULL_LOCK, B_READ_AREA | B_WRITE_AREA ); - - if( area < 0 ) - panic( "Radeon Fast logger: cannot allocate %ld byte for logging data\n", size ); - - li->area = area; - li->log_buffer = (char *)li + sizeof( log_info ); - li->log_buffer_len = size; - li->log_buffer_pos = 0; - - return li; -} - -// clean-up logging -void log_exit( log_info *li ) -{ - li->log_buffer_pos = 0; - //free( li->log_buffer ); - delete_area( li->area ); -} - -#endif - -#endif - - -#ifdef LOG_INCLUDE_STARTUP - -// get *current* size of logging data -uint32 log_getsize( log_info *li ) -{ - if( li == NULL ) - return 0; - - dprintf( "RADEON -- log_getsize: log_pos %ld\n", li->log_buffer_pos ); - return li->log_buffer_pos; -} - -// get up to max_size bytes of logging data -void log_getcopy( log_info *li, void *dest, uint32 max_size ) -{ - if( li == NULL ) - return; - - dprintf( "RADEON -- log_getcopy: max_size %ld, log_pos %ld\n", - max_size, li->log_buffer_pos ); - memcpy( dest, li->log_buffer, min( li->log_buffer_pos, max_size )); - - li->log_buffer_pos = 0; -} - -#endif diff --git a/src/add-ons/kernel/drivers/graphics/common/log_dump.c b/src/add-ons/kernel/drivers/graphics/common/log_dump.c deleted file mode 100644 index fb4d79b8d9..0000000000 --- a/src/add-ons/kernel/drivers/graphics/common/log_dump.c +++ /dev/null @@ -1,73 +0,0 @@ -/* - Copyright (c) 2002, Thomas Kurschel - - - Part of Radeon driver - - Fast logger - functions to create dump -*/ - - -#include -#include - -#include "log_coll.h" -#include "log_dump.h" -#include "log_enum.h" -#include "log_names.h" - -system_info sysinfo; - -// dump one entry -static void log_printentry( FILE *logfile, log_entry *entry ) -{ - uint64 time; - uint32 min, sec, mill, mic; - - time = entry->tsc / (sysinfo.cpu_clock_speed / 1000000); - mic = time % 1000; - time /= 1000; - mill = time % 1000; - time /= 1000; - sec = time % 60; - time /= 60; - min = time; - - fprintf( logfile, "%03ld:%02ld:%03ld.%03ld ", min, sec, mill, mic ); - if( entry->what < sizeof( log_names ) / sizeof( log_names[0] ) ) - fprintf( logfile, log_names[entry->what] ); - else - fprintf( logfile, "unknown %ld", (uint32)entry->what ); - - if( entry->num_args > 0 ) { - uint32 i; - - fprintf( logfile, " (" ); - for( i = 0; i < entry->num_args; ++i ) { - if( i > 0 ) - fprintf( logfile, ", " ); - - fprintf( logfile, "0x%08lx", entry->args[i] ); - } - fprintf( logfile, ")" ); - } - - fprintf( logfile, "\n" ); -} - - -// dump entire log -void log_printall( FILE *logfile, char *buffer, uint32 buffer_len ) -{ - uint32 pos; - - get_system_info( &sysinfo ); - - for( pos = 0; pos < buffer_len; ) { - log_entry *entry; - - entry = (log_entry *)(buffer + pos); - log_printentry( logfile, entry/*, &tsc*/ ); - pos += sizeof( log_entry ) + (entry->num_args - 1) * sizeof( uint32 ); - } -} diff --git a/src/add-ons/kernel/drivers/graphics/common/log_dump.h b/src/add-ons/kernel/drivers/graphics/common/log_dump.h deleted file mode 100644 index bb2a775b91..0000000000 --- a/src/add-ons/kernel/drivers/graphics/common/log_dump.h +++ /dev/null @@ -1,17 +0,0 @@ -/* - Copyright (c) 2002, Thomas Kurschel - - - Part of Radeon accelerant - - Fast logger - functions to create dump -*/ - -#ifndef __LOG_DUMP_H__ -#define __LOG_DUMP_H__ - -#include - -void log_printall( FILE *logfile, char *buffer, uint32 buffer_len ); - -#endif diff --git a/src/add-ons/kernel/drivers/input/usb_hid/HIDDevice.cpp b/src/add-ons/kernel/drivers/input/usb_hid/HIDDevice.cpp index c1e15e1e3b..9348370891 100644 --- a/src/add-ons/kernel/drivers/input/usb_hid/HIDDevice.cpp +++ b/src/add-ons/kernel/drivers/input/usb_hid/HIDDevice.cpp @@ -264,7 +264,7 @@ HIDDevice::MaybeScheduleTransfer() if (fRemoved) return B_ERROR; - if (atomic_set(&fTransferScheduled, 1) != 0) { + if (atomic_get_and_set(&fTransferScheduled, 1) != 0) { // someone else already caused a transfer to be scheduled return B_OK; } diff --git a/src/add-ons/kernel/drivers/misc/poke.c b/src/add-ons/kernel/drivers/misc/poke.c index 91c12931e2..09743d9a44 100644 --- a/src/add-ons/kernel/drivers/misc/poke.c +++ b/src/add-ons/kernel/drivers/misc/poke.c @@ -43,7 +43,7 @@ int32 api_version = B_CUR_DRIVER_API_VERSION; isa_module_info* isa; pci_module_info* pci; -static vint32 open_count; +static int32 open_count; //////////////////////////////////////////////////////////////////////////////// diff --git a/src/add-ons/kernel/drivers/network/sis19x/DataRing.h b/src/add-ons/kernel/drivers/network/sis19x/DataRing.h index af4ebfb625..a3e74aa7e0 100644 --- a/src/add-ons/kernel/drivers/network/sis19x/DataRing.h +++ b/src/add-ons/kernel/drivers/network/sis19x/DataRing.h @@ -43,7 +43,7 @@ private: bool fIsTx; status_t fStatus; area_id fArea; - int32 fSpinlock; + spinlock fSpinlock; sem_id fSemaphore; uint32 fHead; uint32 fTail; @@ -61,12 +61,12 @@ DataRing<__type, __count>::DataRing(Device* device, bool isTx) fIsTx(isTx), fStatus(B_NO_INIT), fArea(-1), - fSpinlock(0), fSemaphore(0), fHead(0), fTail(0), fDescriptors(NULL) { + B_INITIALIZE_SPINLOCK(&fSpinlock); memset(fBuffers, 0, sizeof(fBuffers)); } diff --git a/src/add-ons/kernel/drivers/network/sis19x/Device.cpp b/src/add-ons/kernel/drivers/network/sis19x/Device.cpp index feb94f512a..fb396eadbf 100644 --- a/src/add-ons/kernel/drivers/network/sis19x/Device.cpp +++ b/src/add-ons/kernel/drivers/network/sis19x/Device.cpp @@ -23,7 +23,6 @@ Device::Device(Device::Info &DeviceInfo, pci_info &PCIInfo) fPCIInfo(PCIInfo), fInfo(DeviceInfo), fIOBase(0), - fHWSpinlock(0), fInterruptsNest(0), fFrameSize(MaxFrameSize), fMII(this), @@ -36,6 +35,8 @@ Device::Device(Device::Info &DeviceInfo, pci_info &PCIInfo) { memset((struct timer*)this, 0, sizeof(struct timer)); + B_INITIALIZE_SPINLOCK(&fHWSpinlock); + uint32 cmdRegister = gPCIModule->read_pci_config(PCIInfo.bus, PCIInfo.device, PCIInfo.function, PCI_command, 2); TRACE_ALWAYS("cmdRegister:%#010x\n", cmdRegister); diff --git a/src/add-ons/kernel/drivers/network/sis19x/Device.h b/src/add-ons/kernel/drivers/network/sis19x/Device.h index 30aa6c5eb2..3d73b1326b 100644 --- a/src/add-ons/kernel/drivers/network/sis19x/Device.h +++ b/src/add-ons/kernel/drivers/network/sis19x/Device.h @@ -97,7 +97,7 @@ static int32 _TimerHandler(struct timer* timer); pci_info fPCIInfo; Info& fInfo; int fIOBase; - int32 fHWSpinlock; + spinlock fHWSpinlock; int32 fInterruptsNest; // interface and device infos diff --git a/src/add-ons/kernel/drivers/network/usb_asix/ASIXDevice.h b/src/add-ons/kernel/drivers/network/usb_asix/ASIXDevice.h index 0bccbbfb68..5aa13faf93 100644 --- a/src/add-ons/kernel/drivers/network/usb_asix/ASIXDevice.h +++ b/src/add-ons/kernel/drivers/network/usb_asix/ASIXDevice.h @@ -97,7 +97,7 @@ virtual status_t ReadMACAddress(ether_address_t *address); bool fRemoved; bool fHasConnection; bool fNonBlocking; - vint32 fInsideNotify; + int32 fInsideNotify; // interface and device infos uint16 fFrameSize; diff --git a/src/add-ons/kernel/drivers/network/usb_davicom/DavicomDevice.h b/src/add-ons/kernel/drivers/network/usb_davicom/DavicomDevice.h index af0ce0e0de..233eef2f85 100644 --- a/src/add-ons/kernel/drivers/network/usb_davicom/DavicomDevice.h +++ b/src/add-ons/kernel/drivers/network/usb_davicom/DavicomDevice.h @@ -162,7 +162,7 @@ static void _NotifyCallback(void *cookie, int32 status, bool fHasConnection; bool fTXBufferFull; bool fNonBlocking; - vint32 fInsideNotify; + int32 fInsideNotify; // pipes for notifications, data io and tx packet size usb_pipe fNotifyEndpoint; diff --git a/src/add-ons/kernel/drivers/network/usb_ecm/ECMDevice.h b/src/add-ons/kernel/drivers/network/usb_ecm/ECMDevice.h index 2cc5b266d0..bfbd4e4b35 100644 --- a/src/add-ons/kernel/drivers/network/usb_ecm/ECMDevice.h +++ b/src/add-ons/kernel/drivers/network/usb_ecm/ECMDevice.h @@ -45,7 +45,7 @@ static void _NotifyCallback(void *cookie, int32 status, status_t fStatus; bool fOpen; bool fRemoved; - vint32 fInsideNotify; + int32 fInsideNotify; usb_device fDevice; uint16 fVendorID; uint16 fProductID; diff --git a/src/add-ons/kernel/drivers/power/Jamfile b/src/add-ons/kernel/drivers/power/Jamfile index 01c7932d19..207f29b50d 100644 --- a/src/add-ons/kernel/drivers/power/Jamfile +++ b/src/add-ons/kernel/drivers/power/Jamfile @@ -5,5 +5,4 @@ SubInclude HAIKU_TOP src add-ons kernel drivers power acpi_battery ; SubInclude HAIKU_TOP src add-ons kernel drivers power acpi_button ; SubInclude HAIKU_TOP src add-ons kernel drivers power acpi_lid ; SubInclude HAIKU_TOP src add-ons kernel drivers power acpi_thermal ; -SubInclude HAIKU_TOP src add-ons kernel drivers power enhanced_speedstep ; SubInclude HAIKU_TOP src add-ons kernel drivers power x86_cpuidle ; diff --git a/src/add-ons/kernel/drivers/power/acpi_battery/acpi_battery.cpp b/src/add-ons/kernel/drivers/power/acpi_battery/acpi_battery.cpp index f24724bb8b..9d776fa043 100644 --- a/src/add-ons/kernel/drivers/power/acpi_battery/acpi_battery.cpp +++ b/src/add-ons/kernel/drivers/power/acpi_battery/acpi_battery.cpp @@ -29,7 +29,7 @@ struct battery_driver_cookie { struct battery_device_cookie { battery_driver_cookie* driver_cookie; - vint32 stop_watching; + int32 stop_watching; }; diff --git a/src/add-ons/kernel/drivers/power/enhanced_speedstep/Jamfile b/src/add-ons/kernel/drivers/power/enhanced_speedstep/Jamfile deleted file mode 100644 index 81878167d9..0000000000 --- a/src/add-ons/kernel/drivers/power/enhanced_speedstep/Jamfile +++ /dev/null @@ -1,18 +0,0 @@ -SubDir HAIKU_TOP src add-ons kernel drivers power enhanced_speedstep ; - -SetSubDirSupportedPlatformsBeOSCompatible ; - -if $(TARGET_PLATFORM) != haiku { - # Needed for . Unfortunately we also get the other headers there, - # that we don't really want. - UsePublicHeaders drivers ; -} - -UsePrivateHeaders kernel ; - -KernelAddon enhanced_speedstep : - enhanced_speedstep.cpp - frequency.cpp - ; - -Depends acpi_enhanced_speedstep : acpi ; \ No newline at end of file diff --git a/src/add-ons/kernel/drivers/power/enhanced_speedstep/enhanced_speedstep.cpp b/src/add-ons/kernel/drivers/power/enhanced_speedstep/enhanced_speedstep.cpp deleted file mode 100644 index b332c49ad3..0000000000 --- a/src/add-ons/kernel/drivers/power/enhanced_speedstep/enhanced_speedstep.cpp +++ /dev/null @@ -1,407 +0,0 @@ -/* - * Copyright 2009, Haiku, Inc. All Rights Reserved. - * Distributed under the terms of the MIT License. - * - * Authors: - * Clemens Zeidler, haiku@clemens-zeidler.de - */ - -#include -#include -#include -#include - -#include -#include - -#include - -#include -#include "enhanced_speedstep.h" -#include - -#include "frequency.h" - - -#define EST_MODULE_NAME "drivers/power/enhanced_speedstep/driver_v1" - -#define EST_DEVICE_MODULE_NAME "drivers/power/enhanced_speedstep/device_v1" - -/* Base Namespace devices are published to */ -#define EST_BASENAME "power/enhanced_speedstep/%d" - -// name of pnp generator of path ids -#define EST_PATHID_GENERATOR "enhanced_speedstep/path_id" - -static device_manager_info *sDeviceManager; -static ConditionVariable sFrequencyCondition; -static vint32 sCurrentID; - - -static status_t -est_read(void* _cookie, off_t position, void *buffer, size_t* numBytes) -{ - if (*numBytes < 1) - return B_IO_ERROR; - - est_cookie *device = (est_cookie *)_cookie; - - if (position == 0) { - size_t max_len = *numBytes; - char *str = (char *)buffer; - - snprintf(str, max_len, "CPU Frequency states:\n"); - max_len-= strlen(str); - str += strlen(str); - - freq_info *freqsInfo = device->available_states; - freq_info *f; - for (f = freqsInfo; f->frequency != 0; f++) { - snprintf(str, max_len, " Frequency %hu, Volts %hu, Power %i, " - "Latency %i, id %hu\n", f->frequency, f->volts, f->power, f->id, - EST_TRANS_LAT); - max_len-= strlen(str); - str += strlen(str); - } - - freq_info *f2 = est_get_current(freqsInfo); - if (f2) { - snprintf(str, max_len, "\nCurrent State: Frequency %hu, Volts %hu, " - "Power %i, Latency %i\n", f2->frequency, f2->volts, f2->power, - EST_TRANS_LAT); - } - - *numBytes = strlen((char *)buffer); - } else { - *numBytes = 0; - } - - return B_OK; -} - - -static status_t -est_write(void* cookie, off_t position, const void* buffer, size_t* numBytes) -{ - return B_ERROR; -} - - -status_t -est_control(void* _cookie, uint32 op, void* arg, size_t len) -{ - est_cookie* device = (est_cookie*)_cookie; - status_t err = B_ERROR; - - uint32* magicId; - uint16* id; - freq_info* freqInfo = NULL; - switch (op) { - case IDENTIFY_DEVICE: - if (len < sizeof(uint32)) - return B_IO_ERROR; - magicId = (uint32*)arg; - *magicId = kMagicFreqID; - err = B_OK; - break; - - case GET_CPU_FREQ_STATES: - if (len < sizeof(freq_info) * (device->number_states + 1)) - return B_IO_ERROR; - freqInfo = (freq_info*)arg; - user_memcpy(freqInfo, device->available_states, - sizeof(freq_info) * (device->number_states + 1)); - err = B_OK; - break; - - case GET_CURENT_CPU_FREQ_STATE: - if (len < sizeof(uint16)) - return B_IO_ERROR; - freqInfo = est_get_current(device->available_states); - if (!freqInfo) - return B_ERROR; - atomic_set(&sCurrentID, freqInfo->id); - *((uint16*)arg) = freqInfo->id; - err = B_OK; - break; - - case SET_CPU_FREQ_STATE: - if (len < sizeof(uint16)) - return B_IO_ERROR; - id = (uint16*)arg; - err = est_set_id16(*id); - if (err == B_OK) { - atomic_set(&sCurrentID, *id); - sFrequencyCondition.NotifyAll(); - } - break; - - case WATCH_CPU_FREQ: - if (len < sizeof(uint16)) - return B_IO_ERROR; - sFrequencyCondition.Wait(); - if (atomic_get(&(device->stop_watching))) { - atomic_set(&(device->stop_watching), 0); - err = B_ERROR; - } else { - *((uint16*)arg) = atomic_get(&sCurrentID); - err = B_OK; - } - break; - - case STOP_WATCHING_CPU_FREQ: - atomic_set(&(device->stop_watching), 1); - sFrequencyCondition.NotifyAll(); - err = B_OK; - break; - } - return err; -} - - -static status_t -est_open(void *initCookie, const char *path, int flags, void** cookie) -{ - TRACE("est: open\n"); - est_cookie *device; - device = (est_cookie *)calloc(1, sizeof(est_cookie)); - if (device == NULL) - return B_NO_MEMORY; - - *cookie = device; - - device_node *node = (device_node *)initCookie; - device->node = node; - - device_node *parent; - parent = sDeviceManager->get_parent_node(node); - sDeviceManager->get_driver(parent, (driver_module_info **)&device->acpi, - (void **)&device->acpi_cookie); - sDeviceManager->put_node(parent); - - device->stop_watching = 0; - - // enable enhanced speedstep - uint64 msrMisc = x86_read_msr(MSR_MISC); - if ((msrMisc & MSR_EST_ENABLED) == 0) { - TRACE("est: enable enhanced speedstep\n"); - x86_write_msr(MSR_MISC, msrMisc | MSR_EST_ENABLED); - - uint64 msrMisc = x86_read_msr(MSR_MISC); - if ((msrMisc & MSR_EST_ENABLED) == 0) { - TRACE("est: enable enhanced speedstep failed\n"); - return B_ERROR; - } - } - - // get freq_info - if (est_get_info(&(device->available_states)) != B_OK) - return B_ERROR; - freq_info *freqsInfo = device->available_states; - - // count number of states - TRACE("est: frequency info:\n"); - freq_info *f; - device->number_states = 0; - for (f = freqsInfo; f->frequency != 0; f++) { - TRACE("est: Frequency %u, Volts %u, Power %i, Latency %u, id %u\n", - f->frequency, f->volts, f->power, f->id, EST_TRANS_LAT); - device->number_states++; - } - - // print current frequency - freq_info *f2 = est_get_current(freqsInfo); - if (f2) { - TRACE("est: Current Frequency %u, Volts %u, Power %i, Latency %u\n", - f2->frequency, f2->volts, f2->power, EST_TRANS_LAT); - } - - return B_OK; -} - - -static status_t -est_close(void* cookie) -{ - est_cookie *device = (est_cookie*)cookie; - free(device); - return B_OK; -} - - -static status_t -est_free(void* cookie) -{ - return B_OK; -} - - -// #pragma mark - driver module API - - -static float -est_support(device_node *parent) -{ - // make sure parent is really the ACPI bus manager - const char *bus; - if (sDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false)) - return -1; - - if (strcmp(bus, "acpi")) - return 0.0; - - // check whether it's really a cpu Device - uint32 deviceType; - if (sDeviceManager->get_attr_uint32(parent, ACPI_DEVICE_TYPE_ITEM, - &deviceType, false) != B_OK - || deviceType != ACPI_TYPE_PROCESSOR) { - return 0.0; - } - - // check if cpu support est - uint32 cpuNum = 0; - system_info sysInfo; - if (get_system_info(&sysInfo) != B_OK) - return 0.0; - TRACE("est: cpu_type: %u vendor %u model %u\n", sysInfo.cpu_type, - sysInfo.cpu_type & B_CPU_x86_VENDOR_MASK, sysInfo.cpu_type & 0x00FF); - if ((sysInfo.cpu_type & B_CPU_x86_VENDOR_MASK) != B_CPU_INTEL_x86) - return 0.0; - - // TODO: Make the code SMP safe! - if (sysInfo.cpu_count > 1) - return 0.0; - - cpuid_info info; - if (get_cpuid(&info, 1, cpuNum) != B_OK) - return 0.0; - - TRACE("est: extended_features: %i\n", int(info.eax_1.extended_features)); - - // check for enhanced speedstep - if ((info.eax_1.extended_features & IA32_FEATURE_EXT_EST) == 0) - return 0.0; - - TRACE("est: supported\n"); - return 0.6; -} - - -static status_t -est_register_device(device_node *node) -{ - device_attr attrs[] = { - { B_DEVICE_PRETTY_NAME, B_STRING_TYPE, - { string: "ACPI Enhanced Speedstep" }}, - { NULL } - }; - - return sDeviceManager->register_node(node, EST_MODULE_NAME, attrs, - NULL, NULL); -} - - -static status_t -est_init_driver(device_node *node, void **_driverCookie) -{ - *_driverCookie = node; - - sFrequencyCondition.Init(NULL, "frequency cv"); - sCurrentID = -1; - - return B_OK; -} - - -static void -est_uninit_driver(void *driverCookie) -{ -} - - -static status_t -est_register_child_devices(void *_cookie) -{ - device_node *node = (device_node*)_cookie; - - int pathID = sDeviceManager->create_id(EST_PATHID_GENERATOR); - if (pathID < 0) { - TRACE("est_register_child_devices: couldn't create a path_id\n"); - return B_ERROR; - } - - char name[128]; - snprintf(name, sizeof(name), EST_BASENAME, pathID); - - return sDeviceManager->publish_device(node, name, EST_DEVICE_MODULE_NAME); -} - - -static status_t -est_init_device(void *driverCookie, void **cookie) -{ - // driverCookie is the device node - *cookie = driverCookie; - return B_OK; -} - - -static void -est_uninit_device(void *_cookie) -{ - -} - - - -module_dependency module_dependencies[] = { - { B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&sDeviceManager }, - {} -}; - - -driver_module_info est_driver_module = { - { - EST_MODULE_NAME, - 0, - NULL - }, - - est_support, - est_register_device, - est_init_driver, - est_uninit_driver, - est_register_child_devices, - NULL, // rescan - NULL, // removed -}; - - -struct device_module_info est_device_module = { - { - EST_DEVICE_MODULE_NAME, - 0, - NULL - }, - - est_init_device, - est_uninit_device, - NULL, - - est_open, - est_close, - est_free, - est_read, - est_write, - NULL, - est_control, - - NULL, - NULL -}; - -module_info *modules[] = { - (module_info *)&est_driver_module, - (module_info *)&est_device_module, - NULL -}; diff --git a/src/add-ons/kernel/drivers/power/enhanced_speedstep/enhanced_speedstep.h b/src/add-ons/kernel/drivers/power/enhanced_speedstep/enhanced_speedstep.h deleted file mode 100644 index d511f38dd7..0000000000 --- a/src/add-ons/kernel/drivers/power/enhanced_speedstep/enhanced_speedstep.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef _EST_H -#define _EST_H - -#include -#include - -#include "frequency.h" - -// Model Specific Register -#define MSR_MISC 0x1a0 -#define MSR_EST_ENABLED (1<<16) - - -struct est_cookie { - // this three variables are not needed yet but helpfull when extend this - // driver to use acpi - device_node *node; - acpi_device_module_info *acpi; - acpi_device acpi_cookie; - - // array of states don't delete it - freq_info* available_states; - uint8 number_states; - - vint32 stop_watching; -}; - - -#endif /* _EST_H */ diff --git a/src/add-ons/kernel/drivers/power/enhanced_speedstep/frequency.cpp b/src/add-ons/kernel/drivers/power/enhanced_speedstep/frequency.cpp deleted file mode 100644 index 0c75901c77..0000000000 --- a/src/add-ons/kernel/drivers/power/enhanced_speedstep/frequency.cpp +++ /dev/null @@ -1,202 +0,0 @@ -/* - * Copyright 2009, Haiku, Inc. All Rights Reserved. - * Distributed under the terms of the MIT License. - * - * Authors: - * Clemens Zeidler, haiku@clemens-zeidler.de - */ - - -#include "frequency.h" - -#include - -#include -#include -#include - - -void -est_get_id16(uint16* _id16) -{ - *_id16 = x86_read_msr(MSR_GET_FREQ_STATE) & 0xffff; -} - - -status_t -est_set_id16(uint16 id16, bool needCheck) -{ - uint64 msr; - - // Read the current register, mask out the old, set the new id. - msr = x86_read_msr(MSR_GET_FREQ_STATE); - msr = (msr & ~0xffff) | id16; - x86_write_msr(MSR_SET_FREQ_STATE, msr); - - if (needCheck) { - // Wait a short while for the new setting. XXX Is this necessary? - snooze(EST_TRANS_LAT); - - uint16 newID16; - est_get_id16(&newID16); - if (newID16 != id16) - return B_ERROR; - TRACE("EST: set frequency ok, id %i\n", id16); - } - return B_OK; -} - - -freq_info* -est_get_current(freq_info* list) -{ - // Try a few times to get a valid value. Sometimes, if the CPU - // is in the middle of an asynchronous transition (i.e., P4TCC), - // we get a temporary invalid result. - for (uint32 i = 0; i < 5; i++) { - uint16 id16; - est_get_id16(&id16); - - for (freq_info* info = list; info->id != 0; info++) { - if (info->id == id16) - return info; - } - - snooze(100); - } - return NULL; -} - - -status_t -est_get_info(freq_info** _frequencyInfos) -{ - uint64 msr = x86_read_msr(MSR_GET_FREQ_STATE); - status_t status = est_table_info(msr, _frequencyInfos); - if (status != B_OK) { - TRACE("EST: Get frequency table from model specific register\n"); - status = est_msr_info(msr, _frequencyInfos); - } - - if (status != B_OK) { - TRACE("est: CPU supports Enhanced Speedstep, but is not recognized.\n"); - return status; - } - - return B_OK; -} - - -status_t -est_table_info(uint64 msr, freq_info** _frequencyInfos) -{ - // Find a table which matches (vendor, id32). - system_info info; - if (get_system_info(&info) != B_OK) - return B_ERROR; - - ss_cpu_info* cpuInfo; - uint32 id = msr >> 32; - for (cpuInfo = ESTprocs; cpuInfo->id32 != 0; cpuInfo++) { - if (cpuInfo->vendor_id == uint32(info.cpu_type & B_CPU_x86_VENDOR_MASK) - && cpuInfo->id32 == id) - break; - } - if (cpuInfo->id32 == 0) - return B_ERROR; - - // Make sure the current setpoint is valid. - if (est_get_current(cpuInfo->freqtab) == NULL) { - TRACE("current setting not found in table\n"); - return B_ERROR; - } - - *_frequencyInfos = cpuInfo->freqtab; - return B_OK; -} - - -bool -bus_speed_ok(int bus) -{ - switch (bus) { - case 100: - case 133: - case 166: - case 333: - return true; - default: - return false; - } -} - - -/*! Flesh out a simple rate table containing the high and low frequencies - based on the current clock speed and the upper 32 bits of the MSR. -*/ -status_t -est_msr_info(uint64 msr, freq_info** _frequencyInfos) -{ - // Figure out the bus clock. - system_info info; - if (get_system_info(&info) != B_OK) - return B_ERROR; - - int32 freq = info.cpu_clock_speed / 1000000; - uint16 id = msr >> 32; - int32 bus = 0; - if (id >> 8) - bus = freq / (id >> 8); - - TRACE("est: Guessed bus clock (high) of %d MHz\n", int(bus)); - if (!bus_speed_ok(bus)) { - // We may be running on the low frequency. - id = msr >> 48; - if (id >> 8) - bus = freq / (id >> 8); - TRACE("est: Guessed bus clock (low) of %d MHz\n", int(bus)); - if (!bus_speed_ok(bus)) - return B_ERROR; - - // Calculate high frequency. - id = msr >> 32; - freq = ((id >> 8) & 0xff) * bus; - } - - // Fill out a new freq table containing just the high and low freqs. - freq_info* frequencyInfo = (freq_info*)malloc(sizeof(freq_info) * 3); - if (frequencyInfo == NULL) - return B_NO_MEMORY; - - memset(frequencyInfo, 0, sizeof(freq_info) * 3); - - // First, the high frequency. - int32 volts = id & 0xff; - if (volts != 0) { - volts <<= 4; - volts += 700; - } - frequencyInfo[0].frequency = freq; - frequencyInfo[0].volts = volts; - frequencyInfo[0].id = id; - frequencyInfo[0].power = CPUFREQ_VAL_UNKNOWN; - TRACE("Guessed high setting of %d MHz @ %d Mv\n", int(freq), int(volts)); - - // Second, the low frequency. - id = msr >> 48; - freq = ((id >> 8) & 0xff) * bus; - volts = id & 0xff; - if (volts != 0) { - volts <<= 4; - volts += 700; - } - frequencyInfo[1].frequency = freq; - frequencyInfo[1].volts = volts; - frequencyInfo[1].id = id; - frequencyInfo[1].power = CPUFREQ_VAL_UNKNOWN; - TRACE("Guessed low setting of %d MHz @ %d Mv\n", int(freq), int(volts)); - - // Table is already terminated due to M_ZERO. - *_frequencyInfos = frequencyInfo; - return B_OK; -} diff --git a/src/add-ons/kernel/drivers/power/enhanced_speedstep/frequency.h b/src/add-ons/kernel/drivers/power/enhanced_speedstep/frequency.h deleted file mode 100644 index 454bc6e2bb..0000000000 --- a/src/add-ons/kernel/drivers/power/enhanced_speedstep/frequency.h +++ /dev/null @@ -1,852 +0,0 @@ -#ifndef FREQ_TABLE_H -#define FREQ_TABLE_H - -#include -#include -#include - -#include "device/power_managment.h" - -#define TRACE_EST -#ifdef TRACE_EST -# define TRACE(x...) dprintf(x) -#else -# define TRACE(x...) -#endif - -// this code is taken from freeBSD - -#define MSR_GET_FREQ_STATE 0x198 -#define MSR_SET_FREQ_STATE 0x199 - -/* Estimate in microseconds of latency for performing a transition. */ -#define EST_TRANS_LAT 1000 - -/* Identifying characteristics of a processor and supported frequencies. */ -typedef struct { - const uint32 vendor_id; - uint32 id32; - freq_info *freqtab; -} ss_cpu_info; - - -status_t est_get_info(freq_info **freqsInfo); -status_t est_table_info(uint64 msr, freq_info **freqs); -status_t est_msr_info(uint64 msr, freq_info **freqs); - -freq_info* est_get_current(freq_info *freq_list); -void est_get_id16(uint16 *id16_p); -status_t est_set_id16(uint16 id16, bool need_check = false); - -/* Convert MHz and mV into IDs for passing to the MSR. */ -#define ID16(MHz, mV, bus_clk) \ - (((MHz / bus_clk) << 8) | ((mV ? mV - 700 : 0) >> 4)) -#define ID32(MHz_hi, mV_hi, MHz_lo, mV_lo, bus_clk) \ - ((ID16(MHz_lo, mV_lo, bus_clk) << 16) | (ID16(MHz_hi, mV_hi, bus_clk))) - -/* Format for storing IDs in our table. */ -#define CPUFREQ_VAL_UNKNOWN (-1) -#define CPU_VENDOR_INTEL B_CPU_INTEL_x86 -#define CPU_VENDOR_CENTAUR B_CPU_VIA_IDT_x86 - -#define FREQ_INFO_PWR(MHz, mV, bus_clk, mW) \ - { MHz, mV, ID16(MHz, mV, bus_clk), mW } -#define FREQ_INFO(MHz, mV, bus_clk) \ - FREQ_INFO_PWR(MHz, mV, bus_clk, CPUFREQ_VAL_UNKNOWN) -#define INTEL(tab, zhi, vhi, zlo, vlo, bus_clk) \ - { CPU_VENDOR_INTEL, ID32(zhi, vhi, zlo, vlo, bus_clk), tab } -#define CENTAUR(tab, zhi, vhi, zlo, vlo, bus_clk) \ - { CPU_VENDOR_CENTAUR, ID32(zhi, vhi, zlo, vlo, bus_clk), tab } - -/* Default bus clock value for Centrino processors. */ -#define INTEL_BUS_CLK 100 - -/* - * Frequency (MHz) and voltage (mV) settings. Data from the - * Intel Pentium M Processor Datasheet (Order Number 252612), Table 5. - * - * Dothan processors have multiple VID#s with different settings for - * each VID#. Since we can't uniquely identify this info - * without undisclosed methods from Intel, we can't support newer - * processors with this table method. If ACPI Px states are supported, - * we get info from them. - */ -static freq_info PM17_130[] = { - /* 130nm 1.70GHz Pentium M */ - FREQ_INFO(1700, 1484, INTEL_BUS_CLK), - FREQ_INFO(1400, 1308, INTEL_BUS_CLK), - FREQ_INFO(1200, 1228, INTEL_BUS_CLK), - FREQ_INFO(1000, 1116, INTEL_BUS_CLK), - FREQ_INFO( 800, 1004, INTEL_BUS_CLK), - FREQ_INFO( 600, 956, INTEL_BUS_CLK), - FREQ_INFO( 0, 0, 1), -}; -static freq_info PM16_130[] = { - /* 130nm 1.60GHz Pentium M */ - FREQ_INFO(1600, 1484, INTEL_BUS_CLK), - FREQ_INFO(1400, 1420, INTEL_BUS_CLK), - FREQ_INFO(1200, 1276, INTEL_BUS_CLK), - FREQ_INFO(1000, 1164, INTEL_BUS_CLK), - FREQ_INFO( 800, 1036, INTEL_BUS_CLK), - FREQ_INFO( 600, 956, INTEL_BUS_CLK), - FREQ_INFO( 0, 0, 1), -}; -static freq_info PM15_130[] = { - /* 130nm 1.50GHz Pentium M */ - FREQ_INFO(1500, 1484, INTEL_BUS_CLK), - FREQ_INFO(1400, 1452, INTEL_BUS_CLK), - FREQ_INFO(1200, 1356, INTEL_BUS_CLK), - FREQ_INFO(1000, 1228, INTEL_BUS_CLK), - FREQ_INFO( 800, 1116, INTEL_BUS_CLK), - FREQ_INFO( 600, 956, INTEL_BUS_CLK), - FREQ_INFO( 0, 0, 1), -}; -static freq_info PM14_130[] = { - /* 130nm 1.40GHz Pentium M */ - FREQ_INFO(1400, 1484, INTEL_BUS_CLK), - FREQ_INFO(1200, 1436, INTEL_BUS_CLK), - FREQ_INFO(1000, 1308, INTEL_BUS_CLK), - FREQ_INFO( 800, 1180, INTEL_BUS_CLK), - FREQ_INFO( 600, 956, INTEL_BUS_CLK), - FREQ_INFO( 0, 0, 1), -}; -static freq_info PM13_130[] = { - /* 130nm 1.30GHz Pentium M */ - FREQ_INFO(1300, 1388, INTEL_BUS_CLK), - FREQ_INFO(1200, 1356, INTEL_BUS_CLK), - FREQ_INFO(1000, 1292, INTEL_BUS_CLK), - FREQ_INFO( 800, 1260, INTEL_BUS_CLK), - FREQ_INFO( 600, 956, INTEL_BUS_CLK), - FREQ_INFO( 0, 0, 1), -}; -static freq_info PM13_LV_130[] = { - /* 130nm 1.30GHz Low Voltage Pentium M */ - FREQ_INFO(1300, 1180, INTEL_BUS_CLK), - FREQ_INFO(1200, 1164, INTEL_BUS_CLK), - FREQ_INFO(1100, 1100, INTEL_BUS_CLK), - FREQ_INFO(1000, 1020, INTEL_BUS_CLK), - FREQ_INFO( 900, 1004, INTEL_BUS_CLK), - FREQ_INFO( 800, 988, INTEL_BUS_CLK), - FREQ_INFO( 600, 956, INTEL_BUS_CLK), - FREQ_INFO( 0, 0, 1), -}; -static freq_info PM12_LV_130[] = { - /* 130 nm 1.20GHz Low Voltage Pentium M */ - FREQ_INFO(1200, 1180, INTEL_BUS_CLK), - FREQ_INFO(1100, 1164, INTEL_BUS_CLK), - FREQ_INFO(1000, 1100, INTEL_BUS_CLK), - FREQ_INFO( 900, 1020, INTEL_BUS_CLK), - FREQ_INFO( 800, 1004, INTEL_BUS_CLK), - FREQ_INFO( 600, 956, INTEL_BUS_CLK), - FREQ_INFO( 0, 0, 1), -}; -static freq_info PM11_LV_130[] = { - /* 130 nm 1.10GHz Low Voltage Pentium M */ - FREQ_INFO(1100, 1180, INTEL_BUS_CLK), - FREQ_INFO(1000, 1164, INTEL_BUS_CLK), - FREQ_INFO( 900, 1100, INTEL_BUS_CLK), - FREQ_INFO( 800, 1020, INTEL_BUS_CLK), - FREQ_INFO( 600, 956, INTEL_BUS_CLK), - FREQ_INFO( 0, 0, 1), -}; -static freq_info PM11_ULV_130[] = { - /* 130 nm 1.10GHz Ultra Low Voltage Pentium M */ - FREQ_INFO(1100, 1004, INTEL_BUS_CLK), - FREQ_INFO(1000, 988, INTEL_BUS_CLK), - FREQ_INFO( 900, 972, INTEL_BUS_CLK), - FREQ_INFO( 800, 956, INTEL_BUS_CLK), - FREQ_INFO( 600, 844, INTEL_BUS_CLK), - FREQ_INFO( 0, 0, 1), -}; -static freq_info PM10_ULV_130[] = { - /* 130 nm 1.00GHz Ultra Low Voltage Pentium M */ - FREQ_INFO(1000, 1004, INTEL_BUS_CLK), - FREQ_INFO( 900, 988, INTEL_BUS_CLK), - FREQ_INFO( 800, 972, INTEL_BUS_CLK), - FREQ_INFO( 600, 844, INTEL_BUS_CLK), - FREQ_INFO( 0, 0, 1), -}; - -/* - * Data from "Intel Pentium M Processor on 90nm Process with - * 2-MB L2 Cache Datasheet", Order Number 302189, Table 5. - */ -static freq_info PM_765A_90[] = { - /* 90 nm 2.10GHz Pentium M, VID #A */ - FREQ_INFO(2100, 1340, INTEL_BUS_CLK), - FREQ_INFO(1800, 1276, INTEL_BUS_CLK), - FREQ_INFO(1600, 1228, INTEL_BUS_CLK), - FREQ_INFO(1400, 1180, INTEL_BUS_CLK), - FREQ_INFO(1200, 1132, INTEL_BUS_CLK), - FREQ_INFO(1000, 1084, INTEL_BUS_CLK), - FREQ_INFO( 800, 1036, INTEL_BUS_CLK), - FREQ_INFO( 600, 988, INTEL_BUS_CLK), - FREQ_INFO( 0, 0, 1), -}; -static freq_info PM_765B_90[] = { - /* 90 nm 2.10GHz Pentium M, VID #B */ - FREQ_INFO(2100, 1324, INTEL_BUS_CLK), - FREQ_INFO(1800, 1260, INTEL_BUS_CLK), - FREQ_INFO(1600, 1212, INTEL_BUS_CLK), - FREQ_INFO(1400, 1180, INTEL_BUS_CLK), - FREQ_INFO(1200, 1132, INTEL_BUS_CLK), - FREQ_INFO(1000, 1084, INTEL_BUS_CLK), - FREQ_INFO( 800, 1036, INTEL_BUS_CLK), - FREQ_INFO( 600, 988, INTEL_BUS_CLK), - FREQ_INFO( 0, 0, 1), -}; -static freq_info PM_765C_90[] = { - /* 90 nm 2.10GHz Pentium M, VID #C */ - FREQ_INFO(2100, 1308, INTEL_BUS_CLK), - FREQ_INFO(1800, 1244, INTEL_BUS_CLK), - FREQ_INFO(1600, 1212, INTEL_BUS_CLK), - FREQ_INFO(1400, 1164, INTEL_BUS_CLK), - FREQ_INFO(1200, 1116, INTEL_BUS_CLK), - FREQ_INFO(1000, 1084, INTEL_BUS_CLK), - FREQ_INFO( 800, 1036, INTEL_BUS_CLK), - FREQ_INFO( 600, 988, INTEL_BUS_CLK), - FREQ_INFO( 0, 0, 1), -}; -static freq_info PM_765E_90[] = { - /* 90 nm 2.10GHz Pentium M, VID #E */ - FREQ_INFO(2100, 1356, INTEL_BUS_CLK), - FREQ_INFO(1800, 1292, INTEL_BUS_CLK), - FREQ_INFO(1600, 1244, INTEL_BUS_CLK), - FREQ_INFO(1400, 1196, INTEL_BUS_CLK), - FREQ_INFO(1200, 1148, INTEL_BUS_CLK), - FREQ_INFO(1000, 1100, INTEL_BUS_CLK), - FREQ_INFO( 800, 1052, INTEL_BUS_CLK), - FREQ_INFO( 600, 988, INTEL_BUS_CLK), - FREQ_INFO( 0, 0, 1), -}; -static freq_info PM_755A_90[] = { - /* 90 nm 2.00GHz Pentium M, VID #A */ - FREQ_INFO(2000, 1340, INTEL_BUS_CLK), - FREQ_INFO(1800, 1292, INTEL_BUS_CLK), - FREQ_INFO(1600, 1244, INTEL_BUS_CLK), - FREQ_INFO(1400, 1196, INTEL_BUS_CLK), - FREQ_INFO(1200, 1148, INTEL_BUS_CLK), - FREQ_INFO(1000, 1100, INTEL_BUS_CLK), - FREQ_INFO( 800, 1052, INTEL_BUS_CLK), - FREQ_INFO( 600, 988, INTEL_BUS_CLK), - FREQ_INFO( 0, 0, 1), -}; -static freq_info PM_755B_90[] = { - /* 90 nm 2.00GHz Pentium M, VID #B */ - FREQ_INFO(2000, 1324, INTEL_BUS_CLK), - FREQ_INFO(1800, 1276, INTEL_BUS_CLK), - FREQ_INFO(1600, 1228, INTEL_BUS_CLK), - FREQ_INFO(1400, 1180, INTEL_BUS_CLK), - FREQ_INFO(1200, 1132, INTEL_BUS_CLK), - FREQ_INFO(1000, 1084, INTEL_BUS_CLK), - FREQ_INFO( 800, 1036, INTEL_BUS_CLK), - FREQ_INFO( 600, 988, INTEL_BUS_CLK), - FREQ_INFO( 0, 0, 1), -}; -static freq_info PM_755C_90[] = { - /* 90 nm 2.00GHz Pentium M, VID #C */ - FREQ_INFO(2000, 1308, INTEL_BUS_CLK), - FREQ_INFO(1800, 1276, INTEL_BUS_CLK), - FREQ_INFO(1600, 1228, INTEL_BUS_CLK), - FREQ_INFO(1400, 1180, INTEL_BUS_CLK), - FREQ_INFO(1200, 1132, INTEL_BUS_CLK), - FREQ_INFO(1000, 1084, INTEL_BUS_CLK), - FREQ_INFO( 800, 1036, INTEL_BUS_CLK), - FREQ_INFO( 600, 988, INTEL_BUS_CLK), - FREQ_INFO( 0, 0, 1), -}; -static freq_info PM_755D_90[] = { - /* 90 nm 2.00GHz Pentium M, VID #D */ - FREQ_INFO(2000, 1276, INTEL_BUS_CLK), - FREQ_INFO(1800, 1244, INTEL_BUS_CLK), - FREQ_INFO(1600, 1196, INTEL_BUS_CLK), - FREQ_INFO(1400, 1164, INTEL_BUS_CLK), - FREQ_INFO(1200, 1116, INTEL_BUS_CLK), - FREQ_INFO(1000, 1084, INTEL_BUS_CLK), - FREQ_INFO( 800, 1036, INTEL_BUS_CLK), - FREQ_INFO( 600, 988, INTEL_BUS_CLK), - FREQ_INFO( 0, 0, 1), -}; -static freq_info PM_745A_90[] = { - /* 90 nm 1.80GHz Pentium M, VID #A */ - FREQ_INFO(1800, 1340, INTEL_BUS_CLK), - FREQ_INFO(1600, 1292, INTEL_BUS_CLK), - FREQ_INFO(1400, 1228, INTEL_BUS_CLK), - FREQ_INFO(1200, 1164, INTEL_BUS_CLK), - FREQ_INFO(1000, 1116, INTEL_BUS_CLK), - FREQ_INFO( 800, 1052, INTEL_BUS_CLK), - FREQ_INFO( 600, 988, INTEL_BUS_CLK), - FREQ_INFO( 0, 0, 1), -}; -static freq_info PM_745B_90[] = { - /* 90 nm 1.80GHz Pentium M, VID #B */ - FREQ_INFO(1800, 1324, INTEL_BUS_CLK), - FREQ_INFO(1600, 1276, INTEL_BUS_CLK), - FREQ_INFO(1400, 1212, INTEL_BUS_CLK), - FREQ_INFO(1200, 1164, INTEL_BUS_CLK), - FREQ_INFO(1000, 1116, INTEL_BUS_CLK), - FREQ_INFO( 800, 1052, INTEL_BUS_CLK), - FREQ_INFO( 600, 988, INTEL_BUS_CLK), - FREQ_INFO( 0, 0, 1), -}; -static freq_info PM_745C_90[] = { - /* 90 nm 1.80GHz Pentium M, VID #C */ - FREQ_INFO(1800, 1308, INTEL_BUS_CLK), - FREQ_INFO(1600, 1260, INTEL_BUS_CLK), - FREQ_INFO(1400, 1212, INTEL_BUS_CLK), - FREQ_INFO(1200, 1148, INTEL_BUS_CLK), - FREQ_INFO(1000, 1100, INTEL_BUS_CLK), - FREQ_INFO( 800, 1052, INTEL_BUS_CLK), - FREQ_INFO( 600, 988, INTEL_BUS_CLK), - FREQ_INFO( 0, 0, 1), -}; -static freq_info PM_745D_90[] = { - /* 90 nm 1.80GHz Pentium M, VID #D */ - FREQ_INFO(1800, 1276, INTEL_BUS_CLK), - FREQ_INFO(1600, 1228, INTEL_BUS_CLK), - FREQ_INFO(1400, 1180, INTEL_BUS_CLK), - FREQ_INFO(1200, 1132, INTEL_BUS_CLK), - FREQ_INFO(1000, 1084, INTEL_BUS_CLK), - FREQ_INFO( 800, 1036, INTEL_BUS_CLK), - FREQ_INFO( 600, 988, INTEL_BUS_CLK), - FREQ_INFO( 0, 0, 1), -}; -static freq_info PM_735A_90[] = { - /* 90 nm 1.70GHz Pentium M, VID #A */ - FREQ_INFO(1700, 1340, INTEL_BUS_CLK), - FREQ_INFO(1400, 1244, INTEL_BUS_CLK), - FREQ_INFO(1200, 1180, INTEL_BUS_CLK), - FREQ_INFO(1000, 1116, INTEL_BUS_CLK), - FREQ_INFO( 800, 1052, INTEL_BUS_CLK), - FREQ_INFO( 600, 988, INTEL_BUS_CLK), - FREQ_INFO( 0, 0, 1), -}; -static freq_info PM_735B_90[] = { - /* 90 nm 1.70GHz Pentium M, VID #B */ - FREQ_INFO(1700, 1324, INTEL_BUS_CLK), - FREQ_INFO(1400, 1244, INTEL_BUS_CLK), - FREQ_INFO(1200, 1180, INTEL_BUS_CLK), - FREQ_INFO(1000, 1116, INTEL_BUS_CLK), - FREQ_INFO( 800, 1052, INTEL_BUS_CLK), - FREQ_INFO( 600, 988, INTEL_BUS_CLK), - FREQ_INFO( 0, 0, 1), -}; -static freq_info PM_735C_90[] = { - /* 90 nm 1.70GHz Pentium M, VID #C */ - FREQ_INFO(1700, 1308, INTEL_BUS_CLK), - FREQ_INFO(1400, 1228, INTEL_BUS_CLK), - FREQ_INFO(1200, 1164, INTEL_BUS_CLK), - FREQ_INFO(1000, 1116, INTEL_BUS_CLK), - FREQ_INFO( 800, 1052, INTEL_BUS_CLK), - FREQ_INFO( 600, 988, INTEL_BUS_CLK), - FREQ_INFO( 0, 0, 1), -}; -static freq_info PM_735D_90[] = { - /* 90 nm 1.70GHz Pentium M, VID #D */ - FREQ_INFO(1700, 1276, INTEL_BUS_CLK), - FREQ_INFO(1400, 1212, INTEL_BUS_CLK), - FREQ_INFO(1200, 1148, INTEL_BUS_CLK), - FREQ_INFO(1000, 1100, INTEL_BUS_CLK), - FREQ_INFO( 800, 1052, INTEL_BUS_CLK), - FREQ_INFO( 600, 988, INTEL_BUS_CLK), - FREQ_INFO( 0, 0, 1), -}; -static freq_info PM_725A_90[] = { - /* 90 nm 1.60GHz Pentium M, VID #A */ - FREQ_INFO(1600, 1340, INTEL_BUS_CLK), - FREQ_INFO(1400, 1276, INTEL_BUS_CLK), - FREQ_INFO(1200, 1212, INTEL_BUS_CLK), - FREQ_INFO(1000, 1132, INTEL_BUS_CLK), - FREQ_INFO( 800, 1068, INTEL_BUS_CLK), - FREQ_INFO( 600, 988, INTEL_BUS_CLK), - FREQ_INFO( 0, 0, 1), -}; -static freq_info PM_725B_90[] = { - /* 90 nm 1.60GHz Pentium M, VID #B */ - FREQ_INFO(1600, 1324, INTEL_BUS_CLK), - FREQ_INFO(1400, 1260, INTEL_BUS_CLK), - FREQ_INFO(1200, 1196, INTEL_BUS_CLK), - FREQ_INFO(1000, 1132, INTEL_BUS_CLK), - FREQ_INFO( 800, 1068, INTEL_BUS_CLK), - FREQ_INFO( 600, 988, INTEL_BUS_CLK), - FREQ_INFO( 0, 0, 1), -}; -static freq_info PM_725C_90[] = { - /* 90 nm 1.60GHz Pentium M, VID #C */ - FREQ_INFO(1600, 1308, INTEL_BUS_CLK), - FREQ_INFO(1400, 1244, INTEL_BUS_CLK), - FREQ_INFO(1200, 1180, INTEL_BUS_CLK), - FREQ_INFO(1000, 1116, INTEL_BUS_CLK), - FREQ_INFO( 800, 1052, INTEL_BUS_CLK), - FREQ_INFO( 600, 988, INTEL_BUS_CLK), - FREQ_INFO( 0, 0, 1), -}; -static freq_info PM_725D_90[] = { - /* 90 nm 1.60GHz Pentium M, VID #D */ - FREQ_INFO(1600, 1276, INTEL_BUS_CLK), - FREQ_INFO(1400, 1228, INTEL_BUS_CLK), - FREQ_INFO(1200, 1164, INTEL_BUS_CLK), - FREQ_INFO(1000, 1116, INTEL_BUS_CLK), - FREQ_INFO( 800, 1052, INTEL_BUS_CLK), - FREQ_INFO( 600, 988, INTEL_BUS_CLK), - FREQ_INFO( 0, 0, 1), -}; -static freq_info PM_715A_90[] = { - /* 90 nm 1.50GHz Pentium M, VID #A */ - FREQ_INFO(1500, 1340, INTEL_BUS_CLK), - FREQ_INFO(1200, 1228, INTEL_BUS_CLK), - FREQ_INFO(1000, 1148, INTEL_BUS_CLK), - FREQ_INFO( 800, 1068, INTEL_BUS_CLK), - FREQ_INFO( 600, 988, INTEL_BUS_CLK), - FREQ_INFO( 0, 0, 1), -}; -static freq_info PM_715B_90[] = { - /* 90 nm 1.50GHz Pentium M, VID #B */ - FREQ_INFO(1500, 1324, INTEL_BUS_CLK), - FREQ_INFO(1200, 1212, INTEL_BUS_CLK), - FREQ_INFO(1000, 1148, INTEL_BUS_CLK), - FREQ_INFO( 800, 1068, INTEL_BUS_CLK), - FREQ_INFO( 600, 988, INTEL_BUS_CLK), - FREQ_INFO( 0, 0, 1), -}; -static freq_info PM_715C_90[] = { - /* 90 nm 1.50GHz Pentium M, VID #C */ - FREQ_INFO(1500, 1308, INTEL_BUS_CLK), - FREQ_INFO(1200, 1212, INTEL_BUS_CLK), - FREQ_INFO(1000, 1132, INTEL_BUS_CLK), - FREQ_INFO( 800, 1068, INTEL_BUS_CLK), - FREQ_INFO( 600, 988, INTEL_BUS_CLK), - FREQ_INFO( 0, 0, 1), -}; -static freq_info PM_715D_90[] = { - /* 90 nm 1.50GHz Pentium M, VID #D */ - FREQ_INFO(1500, 1276, INTEL_BUS_CLK), - FREQ_INFO(1200, 1180, INTEL_BUS_CLK), - FREQ_INFO(1000, 1116, INTEL_BUS_CLK), - FREQ_INFO( 800, 1052, INTEL_BUS_CLK), - FREQ_INFO( 600, 988, INTEL_BUS_CLK), - FREQ_INFO( 0, 0, 1), -}; -static freq_info PM_778_90[] = { - /* 90 nm 1.60GHz Low Voltage Pentium M */ - FREQ_INFO(1600, 1116, INTEL_BUS_CLK), - FREQ_INFO(1500, 1116, INTEL_BUS_CLK), - FREQ_INFO(1400, 1100, INTEL_BUS_CLK), - FREQ_INFO(1300, 1084, INTEL_BUS_CLK), - FREQ_INFO(1200, 1068, INTEL_BUS_CLK), - FREQ_INFO(1100, 1052, INTEL_BUS_CLK), - FREQ_INFO(1000, 1052, INTEL_BUS_CLK), - FREQ_INFO( 900, 1036, INTEL_BUS_CLK), - FREQ_INFO( 800, 1020, INTEL_BUS_CLK), - FREQ_INFO( 600, 988, INTEL_BUS_CLK), - FREQ_INFO( 0, 0, 1), -}; -static freq_info PM_758_90[] = { - /* 90 nm 1.50GHz Low Voltage Pentium M */ - FREQ_INFO(1500, 1116, INTEL_BUS_CLK), - FREQ_INFO(1400, 1116, INTEL_BUS_CLK), - FREQ_INFO(1300, 1100, INTEL_BUS_CLK), - FREQ_INFO(1200, 1084, INTEL_BUS_CLK), - FREQ_INFO(1100, 1068, INTEL_BUS_CLK), - FREQ_INFO(1000, 1052, INTEL_BUS_CLK), - FREQ_INFO( 900, 1036, INTEL_BUS_CLK), - FREQ_INFO( 800, 1020, INTEL_BUS_CLK), - FREQ_INFO( 600, 988, INTEL_BUS_CLK), - FREQ_INFO( 0, 0, 1), -}; -static freq_info PM_738_90[] = { - /* 90 nm 1.40GHz Low Voltage Pentium M */ - FREQ_INFO(1400, 1116, INTEL_BUS_CLK), - FREQ_INFO(1300, 1116, INTEL_BUS_CLK), - FREQ_INFO(1200, 1100, INTEL_BUS_CLK), - FREQ_INFO(1100, 1068, INTEL_BUS_CLK), - FREQ_INFO(1000, 1052, INTEL_BUS_CLK), - FREQ_INFO( 900, 1036, INTEL_BUS_CLK), - FREQ_INFO( 800, 1020, INTEL_BUS_CLK), - FREQ_INFO( 600, 988, INTEL_BUS_CLK), - FREQ_INFO( 0, 0, 1), -}; -static freq_info PM_773G_90[] = { - /* 90 nm 1.30GHz Ultra Low Voltage Pentium M, VID #G */ - FREQ_INFO(1300, 956, INTEL_BUS_CLK), - FREQ_INFO(1200, 940, INTEL_BUS_CLK), - FREQ_INFO(1100, 924, INTEL_BUS_CLK), - FREQ_INFO(1000, 908, INTEL_BUS_CLK), - FREQ_INFO( 900, 876, INTEL_BUS_CLK), - FREQ_INFO( 800, 860, INTEL_BUS_CLK), - FREQ_INFO( 600, 812, INTEL_BUS_CLK), -}; -static freq_info PM_773H_90[] = { - /* 90 nm 1.30GHz Ultra Low Voltage Pentium M, VID #H */ - FREQ_INFO(1300, 940, INTEL_BUS_CLK), - FREQ_INFO(1200, 924, INTEL_BUS_CLK), - FREQ_INFO(1100, 908, INTEL_BUS_CLK), - FREQ_INFO(1000, 892, INTEL_BUS_CLK), - FREQ_INFO( 900, 876, INTEL_BUS_CLK), - FREQ_INFO( 800, 860, INTEL_BUS_CLK), - FREQ_INFO( 600, 812, INTEL_BUS_CLK), -}; -static freq_info PM_773I_90[] = { - /* 90 nm 1.30GHz Ultra Low Voltage Pentium M, VID #I */ - FREQ_INFO(1300, 924, INTEL_BUS_CLK), - FREQ_INFO(1200, 908, INTEL_BUS_CLK), - FREQ_INFO(1100, 892, INTEL_BUS_CLK), - FREQ_INFO(1000, 876, INTEL_BUS_CLK), - FREQ_INFO( 900, 860, INTEL_BUS_CLK), - FREQ_INFO( 800, 844, INTEL_BUS_CLK), - FREQ_INFO( 600, 812, INTEL_BUS_CLK), -}; -static freq_info PM_773J_90[] = { - /* 90 nm 1.30GHz Ultra Low Voltage Pentium M, VID #J */ - FREQ_INFO(1300, 908, INTEL_BUS_CLK), - FREQ_INFO(1200, 908, INTEL_BUS_CLK), - FREQ_INFO(1100, 892, INTEL_BUS_CLK), - FREQ_INFO(1000, 876, INTEL_BUS_CLK), - FREQ_INFO( 900, 860, INTEL_BUS_CLK), - FREQ_INFO( 800, 844, INTEL_BUS_CLK), - FREQ_INFO( 600, 812, INTEL_BUS_CLK), -}; -static freq_info PM_773K_90[] = { - /* 90 nm 1.30GHz Ultra Low Voltage Pentium M, VID #K */ - FREQ_INFO(1300, 892, INTEL_BUS_CLK), - FREQ_INFO(1200, 892, INTEL_BUS_CLK), - FREQ_INFO(1100, 876, INTEL_BUS_CLK), - FREQ_INFO(1000, 860, INTEL_BUS_CLK), - FREQ_INFO( 900, 860, INTEL_BUS_CLK), - FREQ_INFO( 800, 844, INTEL_BUS_CLK), - FREQ_INFO( 600, 812, INTEL_BUS_CLK), -}; -static freq_info PM_773L_90[] = { - /* 90 nm 1.30GHz Ultra Low Voltage Pentium M, VID #L */ - FREQ_INFO(1300, 876, INTEL_BUS_CLK), - FREQ_INFO(1200, 876, INTEL_BUS_CLK), - FREQ_INFO(1100, 860, INTEL_BUS_CLK), - FREQ_INFO(1000, 860, INTEL_BUS_CLK), - FREQ_INFO( 900, 844, INTEL_BUS_CLK), - FREQ_INFO( 800, 844, INTEL_BUS_CLK), - FREQ_INFO( 600, 812, INTEL_BUS_CLK), -}; -static freq_info PM_753G_90[] = { - /* 90 nm 1.20GHz Ultra Low Voltage Pentium M, VID #G */ - FREQ_INFO(1200, 956, INTEL_BUS_CLK), - FREQ_INFO(1100, 940, INTEL_BUS_CLK), - FREQ_INFO(1000, 908, INTEL_BUS_CLK), - FREQ_INFO( 900, 892, INTEL_BUS_CLK), - FREQ_INFO( 800, 860, INTEL_BUS_CLK), - FREQ_INFO( 600, 812, INTEL_BUS_CLK), -}; -static freq_info PM_753H_90[] = { - /* 90 nm 1.20GHz Ultra Low Voltage Pentium M, VID #H */ - FREQ_INFO(1200, 940, INTEL_BUS_CLK), - FREQ_INFO(1100, 924, INTEL_BUS_CLK), - FREQ_INFO(1000, 908, INTEL_BUS_CLK), - FREQ_INFO( 900, 876, INTEL_BUS_CLK), - FREQ_INFO( 800, 860, INTEL_BUS_CLK), - FREQ_INFO( 600, 812, INTEL_BUS_CLK), -}; -static freq_info PM_753I_90[] = { - /* 90 nm 1.20GHz Ultra Low Voltage Pentium M, VID #I */ - FREQ_INFO(1200, 924, INTEL_BUS_CLK), - FREQ_INFO(1100, 908, INTEL_BUS_CLK), - FREQ_INFO(1000, 892, INTEL_BUS_CLK), - FREQ_INFO( 900, 876, INTEL_BUS_CLK), - FREQ_INFO( 800, 860, INTEL_BUS_CLK), - FREQ_INFO( 600, 812, INTEL_BUS_CLK), -}; -static freq_info PM_753J_90[] = { - /* 90 nm 1.20GHz Ultra Low Voltage Pentium M, VID #J */ - FREQ_INFO(1200, 908, INTEL_BUS_CLK), - FREQ_INFO(1100, 892, INTEL_BUS_CLK), - FREQ_INFO(1000, 876, INTEL_BUS_CLK), - FREQ_INFO( 900, 860, INTEL_BUS_CLK), - FREQ_INFO( 800, 844, INTEL_BUS_CLK), - FREQ_INFO( 600, 812, INTEL_BUS_CLK), -}; -static freq_info PM_753K_90[] = { - /* 90 nm 1.20GHz Ultra Low Voltage Pentium M, VID #K */ - FREQ_INFO(1200, 892, INTEL_BUS_CLK), - FREQ_INFO(1100, 892, INTEL_BUS_CLK), - FREQ_INFO(1000, 876, INTEL_BUS_CLK), - FREQ_INFO( 900, 860, INTEL_BUS_CLK), - FREQ_INFO( 800, 844, INTEL_BUS_CLK), - FREQ_INFO( 600, 812, INTEL_BUS_CLK), -}; -static freq_info PM_753L_90[] = { - /* 90 nm 1.20GHz Ultra Low Voltage Pentium M, VID #L */ - FREQ_INFO(1200, 876, INTEL_BUS_CLK), - FREQ_INFO(1100, 876, INTEL_BUS_CLK), - FREQ_INFO(1000, 860, INTEL_BUS_CLK), - FREQ_INFO( 900, 844, INTEL_BUS_CLK), - FREQ_INFO( 800, 844, INTEL_BUS_CLK), - FREQ_INFO( 600, 812, INTEL_BUS_CLK), -}; - -static freq_info PM_733JG_90[] = { - /* 90 nm 1.10GHz Ultra Low Voltage Pentium M, VID #G */ - FREQ_INFO(1100, 956, INTEL_BUS_CLK), - FREQ_INFO(1000, 940, INTEL_BUS_CLK), - FREQ_INFO( 900, 908, INTEL_BUS_CLK), - FREQ_INFO( 800, 876, INTEL_BUS_CLK), - FREQ_INFO( 600, 812, INTEL_BUS_CLK), -}; -static freq_info PM_733JH_90[] = { - /* 90 nm 1.10GHz Ultra Low Voltage Pentium M, VID #H */ - FREQ_INFO(1100, 940, INTEL_BUS_CLK), - FREQ_INFO(1000, 924, INTEL_BUS_CLK), - FREQ_INFO( 900, 892, INTEL_BUS_CLK), - FREQ_INFO( 800, 876, INTEL_BUS_CLK), - FREQ_INFO( 600, 812, INTEL_BUS_CLK), -}; -static freq_info PM_733JI_90[] = { - /* 90 nm 1.10GHz Ultra Low Voltage Pentium M, VID #I */ - FREQ_INFO(1100, 924, INTEL_BUS_CLK), - FREQ_INFO(1000, 908, INTEL_BUS_CLK), - FREQ_INFO( 900, 892, INTEL_BUS_CLK), - FREQ_INFO( 800, 860, INTEL_BUS_CLK), - FREQ_INFO( 600, 812, INTEL_BUS_CLK), -}; -static freq_info PM_733JJ_90[] = { - /* 90 nm 1.10GHz Ultra Low Voltage Pentium M, VID #J */ - FREQ_INFO(1100, 908, INTEL_BUS_CLK), - FREQ_INFO(1000, 892, INTEL_BUS_CLK), - FREQ_INFO( 900, 876, INTEL_BUS_CLK), - FREQ_INFO( 800, 860, INTEL_BUS_CLK), - FREQ_INFO( 600, 812, INTEL_BUS_CLK), -}; -static freq_info PM_733JK_90[] = { - /* 90 nm 1.10GHz Ultra Low Voltage Pentium M, VID #K */ - FREQ_INFO(1100, 892, INTEL_BUS_CLK), - FREQ_INFO(1000, 876, INTEL_BUS_CLK), - FREQ_INFO( 900, 860, INTEL_BUS_CLK), - FREQ_INFO( 800, 844, INTEL_BUS_CLK), - FREQ_INFO( 600, 812, INTEL_BUS_CLK), -}; -static freq_info PM_733JL_90[] = { - /* 90 nm 1.10GHz Ultra Low Voltage Pentium M, VID #L */ - FREQ_INFO(1100, 876, INTEL_BUS_CLK), - FREQ_INFO(1000, 876, INTEL_BUS_CLK), - FREQ_INFO( 900, 860, INTEL_BUS_CLK), - FREQ_INFO( 800, 844, INTEL_BUS_CLK), - FREQ_INFO( 600, 812, INTEL_BUS_CLK), -}; -static freq_info PM_733_90[] = { - /* 90 nm 1.10GHz Ultra Low Voltage Pentium M */ - FREQ_INFO(1100, 940, INTEL_BUS_CLK), - FREQ_INFO(1000, 924, INTEL_BUS_CLK), - FREQ_INFO( 900, 892, INTEL_BUS_CLK), - FREQ_INFO( 800, 876, INTEL_BUS_CLK), - FREQ_INFO( 600, 812, INTEL_BUS_CLK), - FREQ_INFO( 0, 0, 1), -}; -static freq_info PM_723_90[] = { - /* 90 nm 1.00GHz Ultra Low Voltage Pentium M */ - FREQ_INFO(1000, 940, INTEL_BUS_CLK), - FREQ_INFO( 900, 908, INTEL_BUS_CLK), - FREQ_INFO( 800, 876, INTEL_BUS_CLK), - FREQ_INFO( 600, 812, INTEL_BUS_CLK), - FREQ_INFO( 0, 0, 1), -}; - -/* - * VIA C7-M 500 MHz FSB, 400 MHz FSB, and ULV variants. - * Data from the "VIA C7-M Processor BIOS Writer's Guide (v2.17)" datasheet. - */ -static freq_info C7M_795[] = { - /* 2.00GHz Centaur C7-M 533 Mhz FSB */ - FREQ_INFO_PWR(2000, 1148, 133, 20000), - FREQ_INFO_PWR(1867, 1132, 133, 18000), - FREQ_INFO_PWR(1600, 1100, 133, 15000), - FREQ_INFO_PWR(1467, 1052, 133, 13000), - FREQ_INFO_PWR(1200, 1004, 133, 10000), - FREQ_INFO_PWR( 800, 844, 133, 7000), - FREQ_INFO_PWR( 667, 844, 133, 6000), - FREQ_INFO_PWR( 533, 844, 133, 5000), - FREQ_INFO(0, 0, 1), -}; -static freq_info C7M_785[] = { - /* 1.80GHz Centaur C7-M 533 Mhz FSB */ - FREQ_INFO_PWR(1867, 1148, 133, 18000), - FREQ_INFO_PWR(1600, 1100, 133, 15000), - FREQ_INFO_PWR(1467, 1052, 133, 13000), - FREQ_INFO_PWR(1200, 1004, 133, 10000), - FREQ_INFO_PWR( 800, 844, 133, 7000), - FREQ_INFO_PWR( 667, 844, 133, 6000), - FREQ_INFO_PWR( 533, 844, 133, 5000), - FREQ_INFO(0, 0, 1), -}; -static freq_info C7M_765[] = { - /* 1.60GHz Centaur C7-M 533 Mhz FSB */ - FREQ_INFO_PWR(1600, 1084, 133, 15000), - FREQ_INFO_PWR(1467, 1052, 133, 13000), - FREQ_INFO_PWR(1200, 1004, 133, 10000), - FREQ_INFO_PWR( 800, 844, 133, 7000), - FREQ_INFO_PWR( 667, 844, 133, 6000), - FREQ_INFO_PWR( 533, 844, 133, 5000), - FREQ_INFO(0, 0, 1), -}; - -static freq_info C7M_794[] = { - /* 2.00GHz Centaur C7-M 400 Mhz FSB */ - FREQ_INFO_PWR(2000, 1148, 100, 20000), - FREQ_INFO_PWR(1800, 1132, 100, 18000), - FREQ_INFO_PWR(1600, 1100, 100, 15000), - FREQ_INFO_PWR(1400, 1052, 100, 13000), - FREQ_INFO_PWR(1000, 1004, 100, 10000), - FREQ_INFO_PWR( 800, 844, 100, 7000), - FREQ_INFO_PWR( 600, 844, 100, 6000), - FREQ_INFO_PWR( 400, 844, 100, 5000), - FREQ_INFO(0, 0, 1), -}; -static freq_info C7M_784[] = { - /* 1.80GHz Centaur C7-M 400 Mhz FSB */ - FREQ_INFO_PWR(1800, 1148, 100, 18000), - FREQ_INFO_PWR(1600, 1100, 100, 15000), - FREQ_INFO_PWR(1400, 1052, 100, 13000), - FREQ_INFO_PWR(1000, 1004, 100, 10000), - FREQ_INFO_PWR( 800, 844, 100, 7000), - FREQ_INFO_PWR( 600, 844, 100, 6000), - FREQ_INFO_PWR( 400, 844, 100, 5000), - FREQ_INFO(0, 0, 1), -}; -static freq_info C7M_764[] = { - /* 1.60GHz Centaur C7-M 400 Mhz FSB */ - FREQ_INFO_PWR(1600, 1084, 100, 15000), - FREQ_INFO_PWR(1400, 1052, 100, 13000), - FREQ_INFO_PWR(1000, 1004, 100, 10000), - FREQ_INFO_PWR( 800, 844, 100, 7000), - FREQ_INFO_PWR( 600, 844, 100, 6000), - FREQ_INFO_PWR( 400, 844, 100, 5000), - FREQ_INFO(0, 0, 1), -}; -static freq_info C7M_754[] = { - /* 1.50GHz Centaur C7-M 400 Mhz FSB */ - FREQ_INFO_PWR(1500, 1004, 100, 12000), - FREQ_INFO_PWR(1400, 988, 100, 11000), - FREQ_INFO_PWR(1000, 940, 100, 9000), - FREQ_INFO_PWR( 800, 844, 100, 7000), - FREQ_INFO_PWR( 600, 844, 100, 6000), - FREQ_INFO_PWR( 400, 844, 100, 5000), - FREQ_INFO(0, 0, 1), -}; -static freq_info C7M_771[] = { - /* 1.20GHz Centaur C7-M 400 Mhz FSB */ - FREQ_INFO_PWR(1200, 860, 100, 7000), - FREQ_INFO_PWR(1000, 860, 100, 6000), - FREQ_INFO_PWR( 800, 844, 100, 5500), - FREQ_INFO_PWR( 600, 844, 100, 5000), - FREQ_INFO_PWR( 400, 844, 100, 4000), - FREQ_INFO(0, 0, 1), -}; - -static freq_info C7M_775_ULV[] = { - /* 1.50GHz Centaur C7-M ULV */ - FREQ_INFO_PWR(1500, 956, 100, 7500), - FREQ_INFO_PWR(1400, 940, 100, 6000), - FREQ_INFO_PWR(1000, 860, 100, 5000), - FREQ_INFO_PWR( 800, 828, 100, 2800), - FREQ_INFO_PWR( 600, 796, 100, 2500), - FREQ_INFO_PWR( 400, 796, 100, 2000), - FREQ_INFO(0, 0, 1), -}; -static freq_info C7M_772_ULV[] = { - /* 1.20GHz Centaur C7-M ULV */ - FREQ_INFO_PWR(1200, 844, 100, 5000), - FREQ_INFO_PWR(1000, 844, 100, 4000), - FREQ_INFO_PWR( 800, 828, 100, 2800), - FREQ_INFO_PWR( 600, 796, 100, 2500), - FREQ_INFO_PWR( 400, 796, 100, 2000), - FREQ_INFO(0, 0, 1), -}; -static freq_info C7M_779_ULV[] = { - /* 1.00GHz Centaur C7-M ULV */ - FREQ_INFO_PWR(1000, 796, 100, 3500), - FREQ_INFO_PWR( 800, 796, 100, 2800), - FREQ_INFO_PWR( 600, 796, 100, 2500), - FREQ_INFO_PWR( 400, 796, 100, 2000), - FREQ_INFO(0, 0, 1), -}; -static freq_info C7M_770_ULV[] = { - /* 1.00GHz Centaur C7-M ULV */ - FREQ_INFO_PWR(1000, 844, 100, 5000), - FREQ_INFO_PWR( 800, 796, 100, 2800), - FREQ_INFO_PWR( 600, 796, 100, 2500), - FREQ_INFO_PWR( 400, 796, 100, 2000), - FREQ_INFO(0, 0, 1), -}; - -static ss_cpu_info ESTprocs[] = { - INTEL(PM17_130, 1700, 1484, 600, 956, INTEL_BUS_CLK), - INTEL(PM16_130, 1600, 1484, 600, 956, INTEL_BUS_CLK), - INTEL(PM15_130, 1500, 1484, 600, 956, INTEL_BUS_CLK), - INTEL(PM14_130, 1400, 1484, 600, 956, INTEL_BUS_CLK), - INTEL(PM13_130, 1300, 1388, 600, 956, INTEL_BUS_CLK), - INTEL(PM13_LV_130, 1300, 1180, 600, 956, INTEL_BUS_CLK), - INTEL(PM12_LV_130, 1200, 1180, 600, 956, INTEL_BUS_CLK), - INTEL(PM11_LV_130, 1100, 1180, 600, 956, INTEL_BUS_CLK), - INTEL(PM11_ULV_130, 1100, 1004, 600, 844, INTEL_BUS_CLK), - INTEL(PM10_ULV_130, 1000, 1004, 600, 844, INTEL_BUS_CLK), - INTEL(PM_765A_90, 2100, 1340, 600, 988, INTEL_BUS_CLK), - INTEL(PM_765B_90, 2100, 1324, 600, 988, INTEL_BUS_CLK), - INTEL(PM_765C_90, 2100, 1308, 600, 988, INTEL_BUS_CLK), - INTEL(PM_765E_90, 2100, 1356, 600, 988, INTEL_BUS_CLK), - INTEL(PM_755A_90, 2000, 1340, 600, 988, INTEL_BUS_CLK), - INTEL(PM_755B_90, 2000, 1324, 600, 988, INTEL_BUS_CLK), - INTEL(PM_755C_90, 2000, 1308, 600, 988, INTEL_BUS_CLK), - INTEL(PM_755D_90, 2000, 1276, 600, 988, INTEL_BUS_CLK), - INTEL(PM_745A_90, 1800, 1340, 600, 988, INTEL_BUS_CLK), - INTEL(PM_745B_90, 1800, 1324, 600, 988, INTEL_BUS_CLK), - INTEL(PM_745C_90, 1800, 1308, 600, 988, INTEL_BUS_CLK), - INTEL(PM_745D_90, 1800, 1276, 600, 988, INTEL_BUS_CLK), - INTEL(PM_735A_90, 1700, 1340, 600, 988, INTEL_BUS_CLK), - INTEL(PM_735B_90, 1700, 1324, 600, 988, INTEL_BUS_CLK), - INTEL(PM_735C_90, 1700, 1308, 600, 988, INTEL_BUS_CLK), - INTEL(PM_735D_90, 1700, 1276, 600, 988, INTEL_BUS_CLK), - INTEL(PM_725A_90, 1600, 1340, 600, 988, INTEL_BUS_CLK), - INTEL(PM_725B_90, 1600, 1324, 600, 988, INTEL_BUS_CLK), - INTEL(PM_725C_90, 1600, 1308, 600, 988, INTEL_BUS_CLK), - INTEL(PM_725D_90, 1600, 1276, 600, 988, INTEL_BUS_CLK), - INTEL(PM_715A_90, 1500, 1340, 600, 988, INTEL_BUS_CLK), - INTEL(PM_715B_90, 1500, 1324, 600, 988, INTEL_BUS_CLK), - INTEL(PM_715C_90, 1500, 1308, 600, 988, INTEL_BUS_CLK), - INTEL(PM_715D_90, 1500, 1276, 600, 988, INTEL_BUS_CLK), - INTEL(PM_778_90, 1600, 1116, 600, 988, INTEL_BUS_CLK), - INTEL(PM_758_90, 1500, 1116, 600, 988, INTEL_BUS_CLK), - INTEL(PM_738_90, 1400, 1116, 600, 988, INTEL_BUS_CLK), - INTEL(PM_773G_90, 1300, 956, 600, 812, INTEL_BUS_CLK), - INTEL(PM_773H_90, 1300, 940, 600, 812, INTEL_BUS_CLK), - INTEL(PM_773I_90, 1300, 924, 600, 812, INTEL_BUS_CLK), - INTEL(PM_773J_90, 1300, 908, 600, 812, INTEL_BUS_CLK), - INTEL(PM_773K_90, 1300, 892, 600, 812, INTEL_BUS_CLK), - INTEL(PM_773L_90, 1300, 876, 600, 812, INTEL_BUS_CLK), - INTEL(PM_753G_90, 1200, 956, 600, 812, INTEL_BUS_CLK), - INTEL(PM_753H_90, 1200, 940, 600, 812, INTEL_BUS_CLK), - INTEL(PM_753I_90, 1200, 924, 600, 812, INTEL_BUS_CLK), - INTEL(PM_753J_90, 1200, 908, 600, 812, INTEL_BUS_CLK), - INTEL(PM_753K_90, 1200, 892, 600, 812, INTEL_BUS_CLK), - INTEL(PM_753L_90, 1200, 876, 600, 812, INTEL_BUS_CLK), - INTEL(PM_733JG_90, 1100, 956, 600, 812, INTEL_BUS_CLK), - INTEL(PM_733JH_90, 1100, 940, 600, 812, INTEL_BUS_CLK), - INTEL(PM_733JI_90, 1100, 924, 600, 812, INTEL_BUS_CLK), - INTEL(PM_733JJ_90, 1100, 908, 600, 812, INTEL_BUS_CLK), - INTEL(PM_733JK_90, 1100, 892, 600, 812, INTEL_BUS_CLK), - INTEL(PM_733JL_90, 1100, 876, 600, 812, INTEL_BUS_CLK), - INTEL(PM_733_90, 1100, 940, 600, 812, INTEL_BUS_CLK), - INTEL(PM_723_90, 1000, 940, 600, 812, INTEL_BUS_CLK), - - CENTAUR(C7M_795, 2000, 1148, 533, 844, 133), - CENTAUR(C7M_794, 2000, 1148, 400, 844, 100), - CENTAUR(C7M_785, 1867, 1148, 533, 844, 133), - CENTAUR(C7M_784, 1800, 1148, 400, 844, 100), - CENTAUR(C7M_765, 1600, 1084, 533, 844, 133), - CENTAUR(C7M_764, 1600, 1084, 400, 844, 100), - CENTAUR(C7M_754, 1500, 1004, 400, 844, 100), - CENTAUR(C7M_775_ULV, 1500, 956, 400, 796, 100), - CENTAUR(C7M_771, 1200, 860, 400, 844, 100), - CENTAUR(C7M_772_ULV, 1200, 844, 400, 796, 100), - CENTAUR(C7M_779_ULV, 1000, 796, 400, 796, 100), - CENTAUR(C7M_770_ULV, 1000, 844, 400, 796, 100), - { 0, 0, NULL }, -}; - -#endif - diff --git a/src/add-ons/kernel/drivers/power/x86_cpuidle/intel_cpuidle.cpp b/src/add-ons/kernel/drivers/power/x86_cpuidle/intel_cpuidle.cpp deleted file mode 100644 index 7f6fbd6c4b..0000000000 --- a/src/add-ons/kernel/drivers/power/x86_cpuidle/intel_cpuidle.cpp +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright 2012, Haiku, Inc. All Rights Reserved. - * Distributed under the terms of the MIT License. - * - * Authors: - * Yongcong Du - */ - -#include -#include -#include - -#include - -#include - -#include "x86_cpuidle.h" - -static CpuidleDevice sIntelDevice; - -static void *kMwaitEax[] = { - // C0, we never use it - (void *)0x00, - // MWAIT C1 - (void *)0x00, - // MWAIT C2 - (void *)0x10, - // MWAIT C3 - (void *)0x20, - // MWAIT C4 - (void *)0x30, - // MWAIT C5 - (void *)0x40, - // MWAIT C6, 0x2 is used to fully shrink L2 cache - (void *)0x52 -}; - - -static int32 -IntelCstateIdleEnter(int32 state, CpuidleDevice *device) -{ - cpu_ent *cpu = get_cpu_struct(); - if (cpu->invoke_scheduler) - return 0; - - CpuidleCstate *cState = &device->cStates[state]; - x86_monitor((void *)&cpu->invoke_scheduler, 0, 0); - if (!cpu->invoke_scheduler) - x86_mwait((unsigned long)cState->pData, 1); - - return state; -} - - -static CpuidleCstate sSnbcStates[CPUIDLE_CSTATE_MAX] = { - {}, - { - "C1-SNB", - 1, - IntelCstateIdleEnter, - }, - { - "C3-SNB", - 80, - IntelCstateIdleEnter, - }, - { - "C6-SNB", - 104, - IntelCstateIdleEnter, - }, - { - "C7-SNB", - 109, - IntelCstateIdleEnter, - }, -}; - - -status_t -intel_cpuidle_init(void) -{ - dprintf("intel idle init\n"); - cpu_ent *cpu = get_cpu_struct(); - if (cpu->arch.vendor != VENDOR_INTEL || cpu->arch.family != 6) - return B_ERROR; - - // Calculated Model Value: M = (Extended Model << 4) + Model - uint32 model = (cpu->arch.extended_model << 4) + cpu->arch.model; - if (model != 0x2a && model != 0x2d) - return B_ERROR; - - cpuid_info cpuid; - get_current_cpuid(&cpuid, 5); - /* ecx[0] monitor/mwait extension supported - * ecx[1] support for treating interrupts as break-events for mwait - * edx number of sub-states - */ - if ((cpuid.regs.ecx & 0x1) == 0 || - (cpuid.regs.ecx & 0x2) == 0 || - cpuid.regs.edx == 0) { - return B_ERROR; - } - - sIntelDevice.cStateCount = 1; - for (int32 i = 1; i < CPUIDLE_CSTATE_MAX; i++) { - int32 subStates = (cpuid.regs.edx >> ((i) * 4)) & 0xf; - // no sub-states means the state is not available - if (!subStates) - continue; - sIntelDevice.cStates[sIntelDevice.cStateCount] = - sSnbcStates[i]; - sIntelDevice.cStates[sIntelDevice.cStateCount].pData = - kMwaitEax[i]; - sIntelDevice.cStateCount++; - } - status_t status = gIdle->AddDevice(&sIntelDevice); - if (status == B_OK) - dprintf("using intel idle\n"); - return status; -} diff --git a/src/add-ons/kernel/file_systems/cdda/Lock.h b/src/add-ons/kernel/file_systems/cdda/Lock.h index e6db2727c5..4c66e6b51d 100644 --- a/src/add-ons/kernel/file_systems/cdda/Lock.h +++ b/src/add-ons/kernel/file_systems/cdda/Lock.h @@ -63,7 +63,7 @@ class Semaphore { private: sem_id fSemaphore; #ifdef USE_BENAPHORE - vint32 fCount; + int32 fCount; #endif }; diff --git a/src/add-ons/kernel/file_systems/nfs4/FileSystem.h b/src/add-ons/kernel/file_systems/nfs4/FileSystem.h index 5ca172d484..5fdca263a1 100644 --- a/src/add-ons/kernel/file_systems/nfs4/FileSystem.h +++ b/src/add-ons/kernel/file_systems/nfs4/FileSystem.h @@ -109,7 +109,7 @@ private: RPC::Server* fServer; - vint64 fId; + int64 fId; dev_t fDevId; InodeIdMap fInoIdMap; diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCServer.h b/src/add-ons/kernel/file_systems/nfs4/RPCServer.h index 35c52f8bc1..50e218b813 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCServer.h +++ b/src/add-ons/kernel/file_systems/nfs4/RPCServer.h @@ -107,7 +107,7 @@ private: uint32 fRepairCount; mutex fRepairLock; - vint32 fXID; + int32 fXID; }; diff --git a/src/add-ons/kernel/generic/Jamfile b/src/add-ons/kernel/generic/Jamfile index 9a1677d11b..1ac20bafc0 100644 --- a/src/add-ons/kernel/generic/Jamfile +++ b/src/add-ons/kernel/generic/Jamfile @@ -3,7 +3,6 @@ SubDir HAIKU_TOP src add-ons kernel generic ; SubInclude HAIKU_TOP src add-ons kernel generic ata_adapter ; SubInclude HAIKU_TOP src add-ons kernel generic atomizer ; SubInclude HAIKU_TOP src add-ons kernel generic bios ; -SubInclude HAIKU_TOP src add-ons kernel generic cpuidle ; SubInclude HAIKU_TOP src add-ons kernel generic dpc ; SubInclude HAIKU_TOP src add-ons kernel generic ide_adapter ; SubInclude HAIKU_TOP src add-ons kernel generic locked_pool ; diff --git a/src/add-ons/kernel/generic/cpuidle/Jamfile b/src/add-ons/kernel/generic/cpuidle/Jamfile deleted file mode 100644 index bb7cdd2746..0000000000 --- a/src/add-ons/kernel/generic/cpuidle/Jamfile +++ /dev/null @@ -1,7 +0,0 @@ -SubDir HAIKU_TOP src add-ons kernel generic cpuidle ; - -UsePrivateKernelHeaders ; - -KernelAddon cpuidle : - cpuidle.cpp - ; diff --git a/src/add-ons/kernel/generic/cpuidle/cpuidle.cpp b/src/add-ons/kernel/generic/cpuidle/cpuidle.cpp deleted file mode 100644 index cc17be8fac..0000000000 --- a/src/add-ons/kernel/generic/cpuidle/cpuidle.cpp +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright 2012, Haiku, Inc. All Rights Reserved. - * Distributed under the terms of the MIT License. - * - * Authors: - * Yongcong Du - */ - -#include -#include -#include - -#include -#include - - -static CpuidleInfo sPerCPU[B_MAX_CPU_COUNT]; -static CpuidleDevice *sDevice; -extern void (*gCpuIdleFunc)(void); - - -/* - * next cstate selection algorithm is based on NetBSD's - * it's simple, stupid - */ -static int32 -SelectCstate(CpuidleInfo *info) -{ - static const int32 csFactor = 3; - - for (int32 i = sDevice->cStateCount - 1; i > 0; i--) { - CpuidleCstate *cState = &sDevice->cStates[i]; - if (info->cstateSleep > cState->latency * csFactor) - return i; - } - - /* Choose C1 if there's no state found */ - return 1; -} - - -static inline void -EnterCstate(int32 state, CpuidleInfo *info) -{ - CpuidleCstate *cstate = &sDevice->cStates[state]; - bigtime_t now = system_time(); - int32 finalState = cstate->EnterIdle(state, sDevice); - if (finalState > 0) { - bigtime_t diff = system_time() - now; - info->cstateSleep = diff; - info->stats[finalState].usageCount++; - info->stats[finalState].usageTime += diff; - } else { - info->cstateSleep = 0; - } -} - - -static void -CpuCstateIdle(void) -{ - CpuidleInfo *info = &sPerCPU[smp_get_current_cpu()]; - int32 state = SelectCstate(info); - EnterCstate(state, info); -} - - -static status_t -std_ops(int32 op, ...) -{ - switch (op) { - case B_MODULE_INIT: - return B_OK; - case B_MODULE_UNINIT: - return B_OK; - } - - return B_ERROR; -} - - -status_t AddDevice(CpuidleDevice *device) -{ - sDevice = device; - memory_write_barrier(); - gCpuIdleFunc = CpuCstateIdle; - return B_OK; -} - - -static CpuidleModuleInfo sCpuidleModule = { - { - B_CPUIDLE_MODULE_NAME, - 0, - std_ops - }, - - AddDevice, -}; - - -module_info *modules[] = { - (module_info *)&sCpuidleModule, - NULL -}; diff --git a/src/add-ons/kernel/network/datalink_protocols/arp/arp.cpp b/src/add-ons/kernel/network/datalink_protocols/arp/arp.cpp index 23a7eaacd1..d2ee6eba0d 100644 --- a/src/add-ons/kernel/network/datalink_protocols/arp/arp.cpp +++ b/src/add-ons/kernel/network/datalink_protocols/arp/arp.cpp @@ -187,7 +187,7 @@ put_request_buffer(arp_entry* entry, net_buffer* buffer) static void delete_request_buffer(arp_entry* entry) { - net_buffer* buffer = atomic_pointer_set(&entry->request_buffer, + net_buffer* buffer = atomic_pointer_get_and_set(&entry->request_buffer, kDeletedBuffer); if (buffer != NULL && buffer != kDeletedBuffer) gBufferModule->free(buffer); diff --git a/src/add-ons/kernel/network/datalink_protocols/ipv6_datagram/ipv6_datagram.cpp b/src/add-ons/kernel/network/datalink_protocols/ipv6_datagram/ipv6_datagram.cpp index 559a1d261d..9d19e8fbe5 100644 --- a/src/add-ons/kernel/network/datalink_protocols/ipv6_datagram/ipv6_datagram.cpp +++ b/src/add-ons/kernel/network/datalink_protocols/ipv6_datagram/ipv6_datagram.cpp @@ -251,7 +251,7 @@ put_request_buffer(ndp_entry* entry, net_buffer* buffer) static void delete_request_buffer(ndp_entry* entry) { - net_buffer* buffer = atomic_pointer_set(&entry->request_buffer, + net_buffer* buffer = atomic_pointer_get_and_set(&entry->request_buffer, kDeletedBuffer); if (buffer != NULL && buffer != kDeletedBuffer) gBufferModule->free(buffer); diff --git a/src/add-ons/kernel/network/stack/net_buffer.cpp b/src/add-ons/kernel/network/stack/net_buffer.cpp index d302c6a7e7..8265d92f2b 100644 --- a/src/add-ons/kernel/network/stack/net_buffer.cpp +++ b/src/add-ons/kernel/network/stack/net_buffer.cpp @@ -166,12 +166,12 @@ static status_t read_data(net_buffer* _buffer, size_t offset, void* data, #if ENABLE_STATS -static vint32 sAllocatedDataHeaderCount = 0; -static vint32 sAllocatedNetBufferCount = 0; -static vint32 sEverAllocatedDataHeaderCount = 0; -static vint32 sEverAllocatedNetBufferCount = 0; -static vint32 sMaxAllocatedDataHeaderCount = 0; -static vint32 sMaxAllocatedNetBufferCount = 0; +static int32 sAllocatedDataHeaderCount = 0; +static int32 sAllocatedNetBufferCount = 0; +static int32 sEverAllocatedDataHeaderCount = 0; +static int32 sEverAllocatedNetBufferCount = 0; +static int32 sMaxAllocatedDataHeaderCount = 0; +static int32 sMaxAllocatedNetBufferCount = 0; #endif diff --git a/src/add-ons/kernel/power/Jamfile b/src/add-ons/kernel/power/Jamfile new file mode 100644 index 0000000000..289cb1f2bc --- /dev/null +++ b/src/add-ons/kernel/power/Jamfile @@ -0,0 +1,5 @@ +SubDir HAIKU_TOP src add-ons kernel power ; + +SubInclude HAIKU_TOP src add-ons kernel power cpufreq ; +SubInclude HAIKU_TOP src add-ons kernel power cpuidle ; + diff --git a/src/add-ons/kernel/power/cpufreq/Jamfile b/src/add-ons/kernel/power/cpufreq/Jamfile new file mode 100644 index 0000000000..163027559b --- /dev/null +++ b/src/add-ons/kernel/power/cpufreq/Jamfile @@ -0,0 +1,4 @@ +SubDir HAIKU_TOP src add-ons kernel power cpufreq ; + +SubInclude HAIKU_TOP src add-ons kernel power cpufreq intel_pstates ; + diff --git a/src/add-ons/kernel/power/cpufreq/intel_pstates/Jamfile b/src/add-ons/kernel/power/cpufreq/intel_pstates/Jamfile new file mode 100644 index 0000000000..22b8211d94 --- /dev/null +++ b/src/add-ons/kernel/power/cpufreq/intel_pstates/Jamfile @@ -0,0 +1,8 @@ +SubDir HAIKU_TOP src add-ons kernel power cpufreq intel_pstates ; + +UsePrivateKernelHeaders ; + +KernelAddon intel_pstates : + intel_pstates.cpp + ; + diff --git a/src/add-ons/kernel/power/cpufreq/intel_pstates/intel_pstates.cpp b/src/add-ons/kernel/power/cpufreq/intel_pstates/intel_pstates.cpp new file mode 100644 index 0000000000..5b545fcd1c --- /dev/null +++ b/src/add-ons/kernel/power/cpufreq/intel_pstates/intel_pstates.cpp @@ -0,0 +1,249 @@ +/* + * Copyright 2013, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, + */ + + +#include +#include + +#include +#include +#include +#include + + +#define INTEL_PSTATES_MODULE_NAME CPUFREQ_MODULES_PREFIX "/intel_pstates/v1" + + +const int kMinimalInterval = 50000; + +static uint16 sMinPState; +static uint16 sMaxPState; +static uint16 sBoostPState; + +static bool sAvoidBoost; + + +struct CPUEntry { + CPUEntry(); + + uint16 fCurrentPState; + + bigtime_t fLastUpdate; +} CACHE_LINE_ALIGN; +static CPUEntry* sCPUEntries; + + +CPUEntry::CPUEntry() + : + fCurrentPState(sMinPState - 1), + fLastUpdate(0) +{ +} + + +static void +pstates_set_scheduler_mode(scheduler_mode mode) +{ + sAvoidBoost = mode == SCHEDULER_MODE_POWER_SAVING; +} + + +static int +measure_pstate(CPUEntry* entry) +{ + InterruptsLocker locker; + + uint64 mperf = x86_read_msr(IA32_MSR_MPERF); + uint64 aperf = x86_read_msr(IA32_MSR_APERF); + + x86_write_msr(IA32_MSR_MPERF, 0); + x86_write_msr(IA32_MSR_APERF, 0); + + locker.Unlock(); + + if (mperf == 0) + return sMinPState; + + int oldPState = sMaxPState * aperf / mperf; + oldPState = min_c(max_c(oldPState, sMinPState), sBoostPState); + + return oldPState; +} + + +static inline void +set_pstate(uint16 pstate) +{ + CPUEntry* entry = &sCPUEntries[smp_get_current_cpu()]; + pstate = min_c(max_c(sMinPState, pstate), sBoostPState); + + if (entry->fCurrentPState != pstate) { + entry->fLastUpdate = system_time(); + entry->fCurrentPState = pstate; + + x86_write_msr(IA32_MSR_PERF_CTL, pstate << 8); + } +} + + +static status_t +pstates_increase_performance(int delta) +{ + CPUEntry* entry = &sCPUEntries[smp_get_current_cpu()]; + + if (system_time() - entry->fLastUpdate < kMinimalInterval) + return B_OK; + + int pState = measure_pstate(entry); + pState += (sBoostPState - pState) * delta / kCPUPerformanceScaleMax; + + if (sAvoidBoost && pState < (sMaxPState + sBoostPState) / 2) + pState = min_c(pState, sMaxPState); + + set_pstate(pState); + return B_OK; +} + + +static status_t +pstates_decrease_performance(int delta) +{ + CPUEntry* entry = &sCPUEntries[smp_get_current_cpu()]; + + if (system_time() - entry->fLastUpdate < kMinimalInterval) + return B_OK; + + int pState = measure_pstate(entry); + pState -= (pState - sMinPState) * delta / kCPUPerformanceScaleMax; + + set_pstate(pState); + return B_OK; +} + + +static bool +is_cpu_model_supported(cpu_ent* cpu) +{ + uint8 model = cpu->arch.model + (cpu->arch.extended_model << 4); + + if (cpu->arch.vendor != VENDOR_INTEL) + return false; + + if (cpu->arch.family != 6) + return false; + + const uint8 kSupportedFamily6Models[] = { + 0x2a, 0x2d, 0x2e, 0x3a, 0x3c, 0x3e, 0x3f, 0x45, 0x46, + }; + const int kSupportedFamily6ModelsCount + = sizeof(kSupportedFamily6Models) / sizeof(uint8); + + int i; + for (i = 0; i < kSupportedFamily6ModelsCount; i++) { + if (model == kSupportedFamily6Models[i]) + break; + } + + return i != kSupportedFamily6ModelsCount; +} + + +static void +set_normal_pstate(void* /* dummy */, int cpu) +{ + measure_pstate(&sCPUEntries[cpu]); + set_pstate(sMaxPState); +} + + +static status_t +init_pstates() +{ + if (!x86_check_feature(IA32_FEATURE_MSR, FEATURE_COMMON)) + return B_ERROR; + + if (!x86_check_feature(IA32_FEATURE_APERFMPERF, FEATURE_6_ECX)) + return B_ERROR; + + int32 cpuCount = smp_get_num_cpus(); + for (int32 i = 0; i < cpuCount; i++) { + if (!is_cpu_model_supported(&gCPU[i])) + return B_ERROR; + } + + sMinPState = (x86_read_msr(IA32_MSR_PLATFORM_INFO) >> 40) & 0xff; + sMaxPState = (x86_read_msr(IA32_MSR_PLATFORM_INFO) >> 8) & 0xff; + sBoostPState + = max_c(x86_read_msr(IA32_MSR_TURBO_RATIO_LIMIT) & 0xff, sMaxPState); + + dprintf("using Intel P-States: min %" B_PRIu16 ", max %" B_PRIu16 + ", boost %" B_PRIu16 "\n", sMinPState, sMaxPState, sBoostPState); + + if (sMaxPState <= sMinPState || sMaxPState == 0) { + dprintf("unexpected or invalid Intel P-States limits, aborting\n"); + return B_ERROR; + } + + sCPUEntries = new(std::nothrow) CPUEntry[cpuCount]; + if (sCPUEntries == NULL) + return B_NO_MEMORY; + + pstates_set_scheduler_mode(SCHEDULER_MODE_LOW_LATENCY); + + call_all_cpus_sync(set_normal_pstate, NULL); + return B_OK; +} + + +static status_t +uninit_pstates() +{ + call_all_cpus_sync(set_normal_pstate, NULL); + delete[] sCPUEntries; + + return B_OK; +} + + +static status_t +std_ops(int32 op, ...) +{ + switch (op) { + case B_MODULE_INIT: + return init_pstates(); + + case B_MODULE_UNINIT: + uninit_pstates(); + return B_OK; + } + + return B_ERROR; +} + + +static cpufreq_module_info sIntelPStates = { + { + INTEL_PSTATES_MODULE_NAME, + 0, + std_ops, + }, + + 1.0f, + + pstates_set_scheduler_mode, + + pstates_increase_performance, + pstates_decrease_performance, +}; + + +module_info* modules[] = { + (module_info*)&sIntelPStates, + NULL +}; + diff --git a/src/add-ons/kernel/power/cpuidle/Jamfile b/src/add-ons/kernel/power/cpuidle/Jamfile new file mode 100644 index 0000000000..702f538988 --- /dev/null +++ b/src/add-ons/kernel/power/cpuidle/Jamfile @@ -0,0 +1,4 @@ +SubDir HAIKU_TOP src add-ons kernel power cpuidle ; + +SubInclude HAIKU_TOP src add-ons kernel power cpuidle intel_cstates ; + diff --git a/src/add-ons/kernel/power/cpuidle/intel_cstates/Jamfile b/src/add-ons/kernel/power/cpuidle/intel_cstates/Jamfile new file mode 100644 index 0000000000..4c8ee487d7 --- /dev/null +++ b/src/add-ons/kernel/power/cpuidle/intel_cstates/Jamfile @@ -0,0 +1,8 @@ +SubDir HAIKU_TOP src add-ons kernel power cpuidle intel_cstates ; + +UsePrivateKernelHeaders ; + +KernelAddon intel_cstates : + intel_cstates.cpp + ; + diff --git a/src/add-ons/kernel/power/cpuidle/intel_cstates/intel_cstates.cpp b/src/add-ons/kernel/power/cpuidle/intel_cstates/intel_cstates.cpp new file mode 100644 index 0000000000..9827c916fd --- /dev/null +++ b/src/add-ons/kernel/power/cpuidle/intel_cstates/intel_cstates.cpp @@ -0,0 +1,217 @@ +/* + * Copyright 2012-2013, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Yongcong Du + * Paweł Dziepak, + */ + + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + + +#define CPUIDLE_CSTATE_MAX 8 + +#define MWAIT_INTERRUPTS_BREAK (1 << 0) + +#define INTEL_CSTATES_MODULE_NAME CPUIDLE_MODULES_PREFIX "/intel_cstates/v1" + +#define BASE_TIME_STEP 500 + +struct CState { + uint32 fCode; + int fSubStatesCount; +}; + +static CState sCStates[CPUIDLE_CSTATE_MAX]; +static int sCStateCount; + +static int sTimeStep = BASE_TIME_STEP; +static bool sEnableWait = false; + +static bigtime_t* sIdleTime; + + +static inline void +x86_monitor(void* address, uint32 ecx, uint32 edx) +{ + asm volatile("monitor" : : "a" (address), "c" (ecx), "d"(edx)); +} + + +static inline void +x86_mwait(uint32 eax, uint32 ecx) +{ + asm volatile("mwait" : : "a" (eax), "c" (ecx)); +} + + +static void +cstates_set_scheduler_mode(scheduler_mode mode) +{ + if (mode == SCHEDULER_MODE_POWER_SAVING) { + sTimeStep = BASE_TIME_STEP / 4; + sEnableWait = true; + } else { + sTimeStep = BASE_TIME_STEP; + sEnableWait = false; + } +} + + +static void +cstates_idle(void) +{ + ASSERT(thread_get_current_thread()->pinned_to_cpu > 0); + int32 cpu = smp_get_current_cpu(); + + bigtime_t timeStep = sTimeStep; + bigtime_t idleTime = sIdleTime[cpu]; + int state = min_c(idleTime / timeStep, sCStateCount - 1); + + ASSERT(state >= 0 && state < sCStateCount); + + int subState = idleTime % timeStep; + subState /= timeStep / sCStates[state].fSubStatesCount; + + ASSERT(subState >= 0 && subState < sCStates[state].fSubStatesCount); + + InterruptsLocker locker; + int dummy; + bigtime_t start = system_time(); + x86_monitor(&dummy, 0, 0); + x86_mwait(sCStates[state].fCode | subState, MWAIT_INTERRUPTS_BREAK); + bigtime_t delta = system_time() - start; + locker.Unlock(); + + sIdleTime[cpu] = (idleTime + delta) / 2; +} + + +static void +cstates_wait(int32* variable, int32 test) +{ + if (!sEnableWait) + return; + + InterruptsLocker _; + x86_monitor(variable, 0, 0); + if (*variable != test) + x86_mwait(sCStates[0].fCode, MWAIT_INTERRUPTS_BREAK); +} + + +static status_t +init_cstates() +{ + if (!x86_check_feature(IA32_FEATURE_EXT_MONITOR, FEATURE_EXT)) + return B_ERROR; + if (!x86_check_feature(IA32_FEATURE_POWER_MWAIT, FEATURE_5_ECX)) + return B_ERROR; + if (!x86_check_feature(IA32_FEATURE_INTERRUPT_MWAIT, FEATURE_5_ECX)) + return B_ERROR; + + // we need invariant TSC + if (!x86_check_feature(IA32_FEATURE_INVARIANT_TSC, FEATURE_EXT_7_EDX)) + return B_ERROR; + + // get C-state data + cpuid_info cpuid; + get_current_cpuid(&cpuid, 0, 0); + uint32 maxBasicLeaf = cpuid.eax_0.max_eax; + if (maxBasicLeaf < 5) + return B_ERROR; + + get_current_cpuid(&cpuid, 5, 0); + if ((cpuid.regs.eax & 0xffff) < sizeof(int32)) + return B_ERROR; + + char cStates[64]; + unsigned int offset = 0; + for (int32 i = 1; i < CPUIDLE_CSTATE_MAX; i++) { + int32 subStates = (cpuid.regs.edx >> (i * 4)) & 0xf; + // no sub-states means the state is not available + if (subStates == 0) + continue; + + if (offset < sizeof(cStates)) { + offset += snprintf(cStates + offset, sizeof(cStates) - offset, + ", C%" B_PRId32, i); + } + + sCStates[sCStateCount].fCode = sCStateCount * 0x10; + sCStates[sCStateCount].fSubStatesCount = subStates; + sCStateCount++; + } + + if (sCStateCount == 0) + return B_ERROR; + + sIdleTime = new(std::nothrow) bigtime_t[smp_get_num_cpus()]; + if (sIdleTime == NULL) + return B_NO_MEMORY; + memset(sIdleTime, 0, sizeof(bigtime_t) * smp_get_num_cpus()); + + cstates_set_scheduler_mode(SCHEDULER_MODE_LOW_LATENCY); + + dprintf("using Intel C-States: C0%s\n", cStates); + return B_OK; +} + + +static status_t +uninit_cstates() +{ + delete[] sIdleTime; + return B_OK; +} + + +static status_t +std_ops(int32 op, ...) +{ + switch (op) { + case B_MODULE_INIT: + return init_cstates(); + + case B_MODULE_UNINIT: + uninit_cstates(); + return B_OK; + } + + return B_ERROR; +} + + +static cpuidle_module_info sIntelCStates = { + { + INTEL_CSTATES_MODULE_NAME, + 0, + std_ops, + }, + + 0.8f, + + cstates_set_scheduler_mode, + + cstates_idle, + cstates_wait +}; + + +module_info* modules[] = { + (module_info*)&sIntelCStates, + NULL +}; + diff --git a/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/IMAPMailbox.h b/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/IMAPMailbox.h index b814919262..b8c53dcd76 100644 --- a/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/IMAPMailbox.h +++ b/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/IMAPMailbox.h @@ -90,7 +90,7 @@ private: ExpungeHandler fExpungeHandler; FlagsHandler fFlagsHandler; - vint32 fWatching; + int32 fWatching; BString fSelectedMailbox; diff --git a/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/IMAPProtocol.h b/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/IMAPProtocol.h index 833e9b7873..bd236fa71a 100644 --- a/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/IMAPProtocol.h +++ b/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/IMAPProtocol.h @@ -120,7 +120,7 @@ private: BString fCommandError; - vint32 fStopNow; + int32 fStopNow; bool fIsConnected; }; diff --git a/src/add-ons/media/media-add-ons/usb_webcam/AddOn.cpp b/src/add-ons/media/media-add-ons/usb_webcam/AddOn.cpp index a115c3f854..13fdb8b9df 100644 --- a/src/add-ons/media/media-add-ons/usb_webcam/AddOn.cpp +++ b/src/add-ons/media/media-add-ons/usb_webcam/AddOn.cpp @@ -179,7 +179,7 @@ WebCamMediaAddOn::FillDefaultFlavorInfo(flavor_info* info) info->info = "USB Web Camera"; info->kinds = B_BUFFER_PRODUCER | B_CONTROLLABLE | B_PHYSICAL_INPUT; info->flavor_flags = 0;//B_FLAVOR_IS_GLOBAL; - info->internal_id = atomic_add((vint32 *)&fInternalIDCounter, 1); + info->internal_id = atomic_add((int32*)&fInternalIDCounter, 1); info->possible_count = 1;//0; info->in_format_count = 0; info->in_format_flags = 0; diff --git a/src/apps/aboutsystem/AboutSystem.cpp b/src/apps/aboutsystem/AboutSystem.cpp index e3224b3013..13e6154009 100644 --- a/src/apps/aboutsystem/AboutSystem.cpp +++ b/src/apps/aboutsystem/AboutSystem.cpp @@ -615,9 +615,40 @@ AboutView::AboutView() strlcpy(processorLabel, B_TRANSLATE("Processor:"), sizeof(processorLabel)); + uint32 topologyNodeCount = 0; + cpu_topology_node_info* topology = NULL; + get_cpu_topology_info(NULL, &topologyNodeCount); + if (topologyNodeCount != 0) + topology = new cpu_topology_node_info[topologyNodeCount]; + get_cpu_topology_info(topology, &topologyNodeCount); + + enum cpu_platform platform = B_CPU_UNKNOWN; + enum cpu_vendor cpuVendor = B_CPU_VENDOR_UNKNOWN; + uint32 cpuModel = 0; + for (uint32 i = 0; i < topologyNodeCount; i++) { + switch (topology[i].type) { + case B_TOPOLOGY_ROOT: + platform = topology[i].data.root.platform; + break; + + case B_TOPOLOGY_PACKAGE: + cpuVendor = topology[i].data.package.vendor; + break; + + case B_TOPOLOGY_CORE: + cpuModel = topology[i].data.core.model; + break; + + default: + break; + } + } + + delete[] topology; + BString cpuType; - cpuType << get_cpu_vendor_string(systemInfo.cpu_type) - << " " << get_cpu_model_string(&systemInfo); + cpuType << get_cpu_vendor_string(cpuVendor) + << " " << get_cpu_model_string(platform, cpuVendor, cpuModel); BStringView* cpuView = new BStringView("cputext", cpuType.String()); cpuView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT, diff --git a/src/apps/activitymonitor/ActivityView.h b/src/apps/activitymonitor/ActivityView.h index 17ac4f89d1..4c9488ec40 100644 --- a/src/apps/activitymonitor/ActivityView.h +++ b/src/apps/activitymonitor/ActivityView.h @@ -76,7 +76,7 @@ public: void RemoveAllDataSources(); bigtime_t RefreshInterval() const - { return atomic_get64((vint64*)&fRefreshInterval); } + { return atomic_get64((int64*)&fRefreshInterval); } protected: virtual void AttachedToWindow(); diff --git a/src/apps/activitymonitor/DataSource.cpp b/src/apps/activitymonitor/DataSource.cpp index b7b15f0d24..c493593f8c 100644 --- a/src/apps/activitymonitor/DataSource.cpp +++ b/src/apps/activitymonitor/DataSource.cpp @@ -497,13 +497,7 @@ BlockCacheDataSource::Copy() const int64 BlockCacheDataSource::NextValue(SystemInfo& info) { - system_memory_info memoryInfo; - status_t status = __get_system_info_etc(B_MEMORY_INFO, &memoryInfo, - sizeof(system_memory_info)); - if (status != B_OK) - return 0; - - return memoryInfo.block_cache_memory; + return info.BlockCacheMemory(); } @@ -873,7 +867,7 @@ CPUUsageDataSource::Print(BString& text, int64 value) const int64 CPUUsageDataSource::NextValue(SystemInfo& info) { - bigtime_t active = info.Info().cpu_infos[fCPU].active_time; + bigtime_t active = info.CPUActiveTime(fCPU); int64 percent = int64(1000.0 * (active - fPreviousActive) / (info.Time() - fPreviousTime)); @@ -1018,8 +1012,8 @@ CPUCombinedUsageDataSource::NextValue(SystemInfo& info) int32 running = 0; bigtime_t active = 0; - for (int32 cpu = 0; cpu < info.Info().cpu_count; cpu++) { - active += info.Info().cpu_infos[cpu].active_time; + for (uint32 cpu = 0; cpu < info.CPUCount(); cpu++) { + active += info.CPUActiveTime(cpu); running++; // TODO: take disabled CPUs into account } diff --git a/src/apps/activitymonitor/SystemInfo.cpp b/src/apps/activitymonitor/SystemInfo.cpp index 423c2bd72d..482fa694c1 100644 --- a/src/apps/activitymonitor/SystemInfo.cpp +++ b/src/apps/activitymonitor/SystemInfo.cpp @@ -24,8 +24,8 @@ SystemInfo::SystemInfo(SystemInfoHandler* handler) fMediaBuffers(0) { get_system_info(&fSystemInfo); - __get_system_info_etc(B_MEMORY_INFO, &fMemoryInfo, - sizeof(system_memory_info)); + fCPUInfos = new cpu_info[fSystemInfo.cpu_count]; + get_cpu_info(0, fSystemInfo.cpu_count, fCPUInfos); if (handler != NULL) { fRunningApps = handler->RunningApps(); @@ -40,6 +40,7 @@ SystemInfo::SystemInfo(SystemInfoHandler* handler) SystemInfo::~SystemInfo() { + delete[] fCPUInfos; } @@ -47,45 +48,53 @@ uint64 SystemInfo::CachedMemory() const { #ifdef __HAIKU__ - return (uint64)fSystemInfo.cached_pages * B_PAGE_SIZE; + return fSystemInfo.cached_pages * B_PAGE_SIZE; #else return 0LL; #endif } +uint64 +SystemInfo::BlockCacheMemory() const +{ + return fSystemInfo.block_cache_pages * B_PAGE_SIZE; +} + + uint64 SystemInfo::UsedMemory() const { - return (uint64)fSystemInfo.used_pages * B_PAGE_SIZE; + return fSystemInfo.used_pages * B_PAGE_SIZE; } uint64 SystemInfo::MaxMemory() const { - return (uint64)fSystemInfo.max_pages * B_PAGE_SIZE; + return fSystemInfo.max_pages * B_PAGE_SIZE; } uint32 SystemInfo::PageFaults() const { - return fMemoryInfo.page_faults; + return fSystemInfo.page_faults; } uint64 SystemInfo::UsedSwapSpace() const { - return fMemoryInfo.max_swap_space - fMemoryInfo.free_swap_space; + return (fSystemInfo.max_swap_pages - fSystemInfo.free_swap_pages) + * B_PAGE_SIZE; } uint64 SystemInfo::MaxSwapSpace() const { - return fMemoryInfo.max_swap_space; + return fSystemInfo.max_swap_pages * B_PAGE_SIZE; } diff --git a/src/apps/activitymonitor/SystemInfo.h b/src/apps/activitymonitor/SystemInfo.h index 2bee16c708..065eb234bd 100644 --- a/src/apps/activitymonitor/SystemInfo.h +++ b/src/apps/activitymonitor/SystemInfo.h @@ -20,6 +20,7 @@ public: ~SystemInfo(); uint64 CachedMemory() const; + uint64 BlockCacheMemory() const; uint64 UsedMemory() const; uint64 MaxMemory() const; @@ -42,6 +43,8 @@ public: bigtime_t Time() const { return fTime; } uint32 CPUCount() const { return fSystemInfo.cpu_count; } + bigtime_t CPUActiveTime(uint32 cpu) const + { return fCPUInfos[cpu].active_time; } const system_info& Info() const { return fSystemInfo; } uint64 NetworkReceived(); @@ -61,7 +64,7 @@ private: void _RetrieveNetwork(); system_info fSystemInfo; - system_memory_info fMemoryInfo; + cpu_info* fCPUInfos; bigtime_t fTime; bool fRetrievedNetwork; uint64 fBytesReceived; diff --git a/src/apps/bsnow/SnowView.cpp b/src/apps/bsnow/SnowView.cpp index 1a3765d9c7..5c3935a236 100644 --- a/src/apps/bsnow/SnowView.cpp +++ b/src/apps/bsnow/SnowView.cpp @@ -87,7 +87,7 @@ SnowView::SnowView(BMessage *archive) fShowClickMe = false; SetFlags(Flags() & ~B_PULSE_NEEDED); /* it's only used when in the app */ get_system_info(&si); - fNumFlakes = ((int32)(si.cpu_clock_speed/1000000)) * si.cpu_count / 3; //; + fNumFlakes = 1000 * si.cpu_count / 3; printf("BSnow: using %ld flakes\n", fNumFlakes); for (int i = 0; i < WORKSPACES_COUNT; i++) { fFlakes[i] = new flake[fNumFlakes]; diff --git a/src/apps/debugger/controllers/DebugReportGenerator.cpp b/src/apps/debugger/controllers/DebugReportGenerator.cpp index 1932d918c8..ceabf32005 100644 --- a/src/apps/debugger/controllers/DebugReportGenerator.cpp +++ b/src/apps/debugger/controllers/DebugReportGenerator.cpp @@ -234,11 +234,40 @@ DebugReportGenerator::_GenerateReportHeader(BString& _output) SystemInfo sysInfo; + uint32 topologyNodeCount = 0; + cpu_topology_node_info* topology = NULL; + get_cpu_topology_info(NULL, &topologyNodeCount); + if (topologyNodeCount != 0) + topology = new cpu_topology_node_info[topologyNodeCount]; + get_cpu_topology_info(topology, &topologyNodeCount); + + cpu_platform platform = B_CPU_UNKNOWN; + cpu_vendor cpuVendor = B_CPU_VENDOR_UNKNOWN; + uint32 cpuModel = 0; + for (uint32 i = 0; i < topologyNodeCount; i++) { + switch (topology[i].type) { + case B_TOPOLOGY_ROOT: + platform = topology[i].data.root.platform; + break; + + case B_TOPOLOGY_PACKAGE: + cpuVendor = topology[i].data.package.vendor; + break; + + case B_TOPOLOGY_CORE: + cpuModel = topology[i].data.core.model; + break; + + default: + break; + } + } + if (fDebuggerInterface->GetSystemInfo(sysInfo) == B_OK) { const system_info &info = sysInfo.GetSystemInfo(); data.SetToFormat("CPU(s): %" B_PRId32 "x %s %s\n", - info.cpu_count, get_cpu_vendor_string(info.cpu_type), - get_cpu_model_string(&info)); + info.cpu_count, get_cpu_vendor_string(cpuVendor), + get_cpu_model_string(platform, cpuVendor, cpuModel)); _output << data; char maxSize[32]; char usedSize[32]; @@ -256,6 +285,7 @@ DebugReportGenerator::_GenerateReportHeader(BString& _output) _output << data; } + delete[] topology; return B_OK; } diff --git a/src/apps/diskprobe/TypeEditors.cpp b/src/apps/diskprobe/TypeEditors.cpp index 39bfbf8cb2..3cf2d46948 100644 --- a/src/apps/diskprobe/TypeEditors.cpp +++ b/src/apps/diskprobe/TypeEditors.cpp @@ -187,7 +187,7 @@ TypeEditorView::TypeMatches() system_info info; get_system_info(&info); - return fEditor.FileSize() / B_PAGE_SIZE < info.max_pages / 2; + return uint64(fEditor.FileSize()) / B_PAGE_SIZE < info.max_pages / 2; } diff --git a/src/apps/icon-o-matic/generic/support/Referenceable.h b/src/apps/icon-o-matic/generic/support/Referenceable.h index 00cdf55438..6539324e9f 100644 --- a/src/apps/icon-o-matic/generic/support/Referenceable.h +++ b/src/apps/icon-o-matic/generic/support/Referenceable.h @@ -21,7 +21,7 @@ class Referenceable { bool Release(); private: - vint32 fReferenceCount; + int32 fReferenceCount; }; #endif // REFERENCABLE_H diff --git a/src/apps/packageinstaller/PackageInfo.cpp b/src/apps/packageinstaller/PackageInfo.cpp index c94d49f76f..c1410029bf 100644 --- a/src/apps/packageinstaller/PackageInfo.cpp +++ b/src/apps/packageinstaller/PackageInfo.cpp @@ -45,6 +45,21 @@ enum { P_SCRIPT }; +typedef enum { + B_BEBOX_PLATFORM = 0, + B_MAC_PLATFORM, + B_AT_CLONE_PLATFORM, + B_ENIAC_PLATFORM, + B_APPLE_II_PLATFORM, + B_CRAY_PLATFORM, + B_LISA_PLATFORM, + B_TI_994A_PLATFORM, + B_TIMEX_SINCLAIR_PLATFORM, + B_ORAC_1_PLATFORM, + B_HAL_PLATFORM, + B_INVALID_PLATFORM +} platform_type; + PackageInfo::PackageInfo() : @@ -131,8 +146,19 @@ PackageInfo::Parse() const char padding[7] = { 0, 0, 0, 0, 0, 0, 0 }; - system_info sysinfo; - get_system_info(&sysinfo); + platform_type thisPlatform = B_INVALID_PLATFORM; + cpu_topology_node_info topologyRoot; + uint32 topologyNodeCount = 1; + if (get_cpu_topology_info(&topologyRoot, &topologyNodeCount) == B_OK) { + switch (topologyRoot.data.root.platform) { + case B_CPU_x86: + thisPlatform = B_AT_CLONE_PLATFORM; + break; + + default: + break; + } + } uint64 infoOffset = 0, groupsOffset = 0; uint64 length = 0; @@ -843,8 +869,7 @@ PackageInfo::Parse() parser_debug("Padding!\n"); if (platform != 0xffffffff - && static_cast(platform) - != sysinfo.platform_type) { + && static_cast(platform) != thisPlatform) { // If the file/directory/item's platform is different than the // target platform (or different than the 'any' constant), // ignore this file diff --git a/src/apps/powerstatus/DriverInterface.h b/src/apps/powerstatus/DriverInterface.h index 52194b68e8..fd196bc518 100644 --- a/src/apps/powerstatus/DriverInterface.h +++ b/src/apps/powerstatus/DriverInterface.h @@ -67,7 +67,7 @@ public: protected: virtual void _WatchPowerStatus() = 0; - vint32 fIsWatching; + int32 fIsWatching; sem_id fWaitSem; private: diff --git a/src/apps/processcontroller/MemoryBarMenu.cpp b/src/apps/processcontroller/MemoryBarMenu.cpp index cdd8a925b4..125189dee0 100644 --- a/src/apps/processcontroller/MemoryBarMenu.cpp +++ b/src/apps/processcontroller/MemoryBarMenu.cpp @@ -45,7 +45,7 @@ MemoryBarMenu::MemoryBarMenu(const char* name, info_pack* infos, system_info& sy fTeamList = (team_id*)malloc(sizeof (team_id) * fTeamCount); - int k; + unsigned int k; for (k = 0; k < systemInfo.used_teams; k++) { fTeamList[k] = infos[k].team_info.team; } @@ -124,7 +124,7 @@ MemoryBarMenu::Pulse() info_pack infos; item = NULL; while (get_next_team_info(&cookie, &infos.team_info) == B_OK) { - int j = 0; + unsigned int j = 0; while (j < fTeamCount && infos.team_info.team != fTeamList[j]) { j++; } diff --git a/src/apps/processcontroller/MemoryBarMenu.h b/src/apps/processcontroller/MemoryBarMenu.h index 7f54961c41..627619608f 100644 --- a/src/apps/processcontroller/MemoryBarMenu.h +++ b/src/apps/processcontroller/MemoryBarMenu.h @@ -44,7 +44,7 @@ class MemoryBarMenu : public BMenu { private: team_id* fTeamList; - int fTeamCount; + unsigned int fTeamCount; MRecycleItem* fRecycleList; int fRecycleCount; bigtime_t fLastTotalTime; diff --git a/src/apps/processcontroller/ProcessController.cpp b/src/apps/processcontroller/ProcessController.cpp index 4925f065f3..8204e33bc6 100644 --- a/src/apps/processcontroller/ProcessController.cpp +++ b/src/apps/processcontroller/ProcessController.cpp @@ -42,6 +42,7 @@ #include #include +#include #include #include "AutoIcon.h" @@ -76,7 +77,7 @@ const rgb_color kKernelBlue = {20, 20, 231, 255}; const rgb_color kIdleGreen = {110, 190,110, 255}; ProcessController* gPCView; -int32 gCPUcount; +uint32 gCPUcount; rgb_color gUserColor; rgb_color gUserColorSelected; rgb_color gIdleColor; @@ -157,7 +158,11 @@ ProcessController::ProcessController(BRect frame, bool temp) fTrackerIcon(kTrackerSig), fDeskbarIcon(kDeskbarSig), fTerminalIcon(kTerminalSig), - fTemp(temp) + kCPUCount(sysconf(_SC_NPROCESSORS_CONF)), + fTemp(temp), + fLastBarHeight(new float[kCPUCount]), + fCPUTimes(new double[kCPUCount]), + fPrevActive(new bigtime_t[kCPUCount]) { if (!temp) { Init(); @@ -177,7 +182,11 @@ ProcessController::ProcessController(BMessage *data) fTrackerIcon(kTrackerSig), fDeskbarIcon(kDeskbarSig), fTerminalIcon(kTerminalSig), - fTemp(false) + kCPUCount(sysconf(_SC_NPROCESSORS_CONF)), + fTemp(false), + fLastBarHeight(new float[kCPUCount]), + fCPUTimes(new double[kCPUCount]), + fPrevActive(new bigtime_t[kCPUCount]) { Init(); } @@ -190,7 +199,11 @@ ProcessController::ProcessController() fTrackerIcon(kTrackerSig), fDeskbarIcon(kDeskbarSig), fTerminalIcon(kTerminalSig), - fTemp(false) + kCPUCount(sysconf(_SC_NPROCESSORS_CONF)), + fTemp(false), + fLastBarHeight(new float[kCPUCount]), + fCPUTimes(new double[kCPUCount]), + fPrevActive(new bigtime_t[kCPUCount]) { Init(); } @@ -207,12 +220,20 @@ ProcessController::~ProcessController() delete fMessageRunner; gPCView = NULL; + + delete[] fPrevActive; + delete[] fCPUTimes; + delete[] fLastBarHeight; } void ProcessController::Init() { + memset(fLastBarHeight, 0, sizeof(float) * kCPUCount); + memset(fCPUTimes, 0, sizeof(double) * kCPUCount); + memset(fPrevActive, 0, sizeof(bigtime_t) * kCPUCount); + gPCView = this; fMessageRunner = NULL; memset(fLastBarHeight, 0, sizeof(fLastBarHeight)); @@ -418,10 +439,10 @@ ProcessController::MessageReceived(BMessage *message) case 'CPU ': { - int32 cpu; - if (message->FindInt32 ("cpu", &cpu) == B_OK) { + uint32 cpu; + if (message->FindInt32("cpu", (int32*)&cpu) == B_OK) { bool last = true; - for (int p = 0; p < gCPUcount; p++) { + for (unsigned int p = 0; p < gCPUcount; p++) { if (p != cpu && _kern_cpu_enabled(p)) { last = false; break; @@ -441,6 +462,14 @@ ProcessController::MessageReceived(BMessage *message) break; } + case 'Schd': + { + int32 mode; + if (message->FindInt32 ("mode", &mode) == B_OK) + set_scheduler_mode(mode); + break; + } + case B_ABOUT_REQUESTED: AboutRequested(); break; @@ -584,7 +613,7 @@ ProcessController::DoDraw(bool force) SetHighColor(frame_color); StrokeRect(BRect(left - 1, top - 1, right, bottom + 1)); if (gCPUcount > 1 && layout[gCPUcount].cpu_inter == 1) { - for (int x = 1; x < gCPUcount; x++) + for (unsigned int x = 1; x < gCPUcount; x++) StrokeLine(BPoint(left + x * barWidth + x - 1, top), BPoint(left + x * barWidth + x - 1, bottom)); } @@ -594,7 +623,7 @@ ProcessController::DoDraw(bool force) StrokeRect(BRect(leftMem - 1, top - 1, leftMem + layout[gCPUcount].mem_width, bottom + 1)); - for (int x = 0; x < gCPUcount; x++) { + for (unsigned int x = 0; x < gCPUcount; x++) { right = left + barWidth - 1; float rem = fCPUTimes[x] * (h + 1); float barHeight = floorf (rem); @@ -672,14 +701,17 @@ ProcessController::Update() get_system_info(&info); bigtime_t now = system_time(); + cpu_info* cpuInfos = new cpu_info[gCPUcount]; + get_cpu_info(0, gCPUcount, cpuInfos); + fMemoryUsage = float(info.used_pages) / float(info.max_pages); // Calculate work done since last call to Update() for each CPU - for (int x = 0; x < gCPUcount; x++) { - bigtime_t load = info.cpu_infos[x].active_time - fPrevActive[x]; + for (unsigned int x = 0; x < gCPUcount; x++) { + bigtime_t load = cpuInfos[x].active_time - fPrevActive[x]; bigtime_t passed = now - fPrevTime; float cpuTime = float(load) / float(passed); - fPrevActive[x] = info.cpu_infos[x].active_time; + fPrevActive[x] = cpuInfos[x].active_time; if (load > passed) fPrevActive[x] -= load - passed; // save overload for next period... if (cpuTime < 0) @@ -689,6 +721,8 @@ ProcessController::Update() fCPUTimes[x] = cpuTime; } fPrevTime = now; + + delete[] cpuInfos; } @@ -700,7 +734,8 @@ thread_popup(void *arg) { Tpopup_param* param = (Tpopup_param*) arg; int32 mcookie, hcookie; - long m, h; + unsigned long m; + long h; BMenuItem* item; bool top = param->top; @@ -772,7 +807,7 @@ thread_popup(void *arg) // CPU on/off section if (gCPUcount > 1) { - for (int i = 0; i < gCPUcount; i++) { + for (unsigned int i = 0; i < gCPUcount; i++) { char item_name[32]; sprintf (item_name, B_TRANSLATE("Processor %d"), i + 1); BMessage* m = new BMessage ('CPU '); @@ -786,6 +821,21 @@ thread_popup(void *arg) addtopbottom (new BSeparatorItem ()); } + // Scheduler modes + static const char* schedulerModes[] = { "Low Latency", "Power Saving" }; + unsigned int modesCount = sizeof(schedulerModes) / sizeof(const char*); + int32 currentMode = get_scheduler_mode(); + for (unsigned int i = 0; i < modesCount; i++) { + BMessage* m = new BMessage('Schd'); + m->AddInt32("mode", i); + item = new BMenuItem(B_TRANSLATE(schedulerModes[i]), m); + if ((uint32)currentMode == i) + item->SetMarked(true); + item->SetTarget(gPCView); + addtopbottom(item); + } + addtopbottom(new BSeparatorItem()); + if (!be_roster->IsRunning(kTrackerSig)) { item = new IconMenuItem(gPCView->fTrackerIcon, B_TRANSLATE("Restart Tracker"), new BMessage('Trac')); diff --git a/src/apps/processcontroller/ProcessController.h b/src/apps/processcontroller/ProcessController.h index 02cd76f067..8317d17747 100644 --- a/src/apps/processcontroller/ProcessController.h +++ b/src/apps/processcontroller/ProcessController.h @@ -60,19 +60,20 @@ class ProcessController : public BView { void Init(); void _HandleDebugRequest(team_id team, thread_id thread); + const int32 kCPUCount; bool fTemp; float fMemoryUsage; - float fLastBarHeight[B_MAX_CPU_COUNT]; + float* fLastBarHeight; float fLastMemoryHeight; - double fCPUTimes[B_MAX_CPU_COUNT]; - bigtime_t fPrevActive[B_MAX_CPU_COUNT]; + double* fCPUTimes; + bigtime_t* fPrevActive; bigtime_t fPrevTime; BMessageRunner* fMessageRunner; rgb_color frame_color, active_color, idle_color, memory_color, swap_color; }; extern ProcessController* gPCView; -extern int32 gCPUcount; +extern uint32 gCPUcount; extern rgb_color gIdleColor; extern rgb_color gIdleColorSelected; extern rgb_color gKernelColor; diff --git a/src/apps/processcontroller/TeamBarMenuItem.cpp b/src/apps/processcontroller/TeamBarMenuItem.cpp index 3c9e5e477a..5806a6ebac 100644 --- a/src/apps/processcontroller/TeamBarMenuItem.cpp +++ b/src/apps/processcontroller/TeamBarMenuItem.cpp @@ -51,7 +51,7 @@ TeamBarMenuItem::Init() if (fTeamID == B_SYSTEM_TEAM) { thread_info thinfos; bigtime_t idle = 0; - for (int t = 1; t <= gCPUcount; t++) + for (unsigned int t = 1; t <= gCPUcount; t++) if (get_thread_info(t, &thinfos) == B_OK) idle += thinfos.kernel_time + thinfos.user_time; fTeamUsageInfo.kernel_time += fTeamUsageInfo.user_time; @@ -213,9 +213,10 @@ TeamBarMenuItem::BarUpdate() bigtime_t idle = 0; if (fTeamID == B_SYSTEM_TEAM) { thread_info thinfos; - for (int t = 1; t <= gCPUcount; t++) + for (unsigned int t = 1; t <= gCPUcount; t++) { if (get_thread_info(t, &thinfos) == B_OK) idle += thinfos.kernel_time + thinfos.user_time; + } usage.kernel_time += usage.user_time; usage.user_time = idle; idle -= fTeamUsageInfo.user_time; diff --git a/src/apps/processcontroller/ThreadBarMenuItem.cpp b/src/apps/processcontroller/ThreadBarMenuItem.cpp index 8af186b7ad..94b2d1dd8c 100644 --- a/src/apps/processcontroller/ThreadBarMenuItem.cpp +++ b/src/apps/processcontroller/ThreadBarMenuItem.cpp @@ -104,10 +104,16 @@ ThreadBarMenuItem::DrawBar(bool force) r.right = fGrenze1; } if (r.left < r.right) { - if (selected) - menu->SetHighColor(fThreadID <= gCPUcount ? gIdleColorSelected : gUserColorSelected); - else - menu->SetHighColor(fThreadID <= gCPUcount ? gIdleColor : gUserColor); + thread_info threadInfo; + bool idleThread = false; + if (get_thread_info(fThreadID, &threadInfo) == B_OK) + idleThread = threadInfo.priority == B_IDLE_PRIORITY; + + if (selected) { + menu->SetHighColor( + idleThread ? gIdleColorSelected : gUserColorSelected); + } else + menu->SetHighColor(idleThread ? gIdleColor : gUserColor); menu->FillRect(r); } r.left = grenze2; @@ -157,7 +163,7 @@ ThreadBarMenuItem::BarUpdate() bigtime_t now = system_time(); fKernel = double(info.kernel_time - fThreadInfo.kernel_time) / double(now - fLastTime); fUser = double(info.user_time - fThreadInfo.user_time) / double(now - fLastTime); - if (fThreadID <= gCPUcount) { + if (info.priority == B_IDLE_PRIORITY) { fUser += fKernel; fKernel = 0; } diff --git a/src/apps/pulse/DeskbarPulseView.cpp b/src/apps/pulse/DeskbarPulseView.cpp index 959c49daca..b20c3236f0 100644 --- a/src/apps/pulse/DeskbarPulseView.cpp +++ b/src/apps/pulse/DeskbarPulseView.cpp @@ -75,9 +75,8 @@ void DeskbarPulseView::AttachedToWindow() { system_info sys_info; get_system_info(&sys_info); if (sys_info.cpu_count >= 2) { - for (int x = 0; x < sys_info.cpu_count; x++) { + for (unsigned int x = 0; x < sys_info.cpu_count; x++) cpu_menu_items[x]->SetTarget(messenger); - } } // Use a BMessageRunner to deliver periodic messsages instead diff --git a/src/apps/pulse/MiniPulseView.cpp b/src/apps/pulse/MiniPulseView.cpp index e36089869c..32804892e2 100644 --- a/src/apps/pulse/MiniPulseView.cpp +++ b/src/apps/pulse/MiniPulseView.cpp @@ -64,7 +64,7 @@ MiniPulseView::MiniPulseView(BMessage *message) void MiniPulseView::Draw(BRect rect) { system_info sys_info; get_system_info(&sys_info); - if (sys_info.cpu_count > B_MAX_CPU_COUNT || sys_info.cpu_count <= 0) + if (sys_info.cpu_count <= 0) return; BRect bounds(Bounds()); @@ -76,7 +76,7 @@ void MiniPulseView::Draw(BRect rect) { float bar_width = (bounds.Width()) / sys_info.cpu_count - 2; float right = bar_width + left; - for (int x = 0; x < sys_info.cpu_count; x++) { + for (unsigned int x = 0; x < sys_info.cpu_count; x++) { int bar_height = (int)(cpu_times[x] * (h + 1)); if (bar_height > h) bar_height = h; double rem = cpu_times[x] * (h + 1) - bar_height; @@ -131,9 +131,8 @@ void MiniPulseView::AttachedToWindow() { system_info sys_info; get_system_info(&sys_info); if (sys_info.cpu_count >= 2) { - for (int x = 0; x < sys_info.cpu_count; x++) { + for (unsigned int x = 0; x < sys_info.cpu_count; x++) cpu_menu_items[x]->SetTarget(messenger); - } } } diff --git a/src/apps/pulse/NormalPulseView.cpp b/src/apps/pulse/NormalPulseView.cpp index 632b6bfa5c..c23dd24b69 100644 --- a/src/apps/pulse/NormalPulseView.cpp +++ b/src/apps/pulse/NormalPulseView.cpp @@ -129,16 +129,34 @@ NormalPulseView::DetermineVendorAndProcessor() logo = PowerPCLogo; #endif #if __INTEL__ - - switch (sys_info.cpu_type & B_CPU_x86_VENDOR_MASK) { - case B_CPU_INTEL_x86: - logo = IntelLogo; - break; - - case B_CPU_AMD_x86: - logo = AmdLogo; - break; - }; + uint32 topologyNodeCount = 0; + cpu_topology_node_info* topology = NULL; + + get_cpu_topology_info(NULL, &topologyNodeCount); + if (topologyNodeCount != 0) + topology = new cpu_topology_node_info[topologyNodeCount]; + get_cpu_topology_info(topology, &topologyNodeCount); + + for (uint32 i = 0; i < topologyNodeCount; i++) { + if (topology[i].type == B_TOPOLOGY_PACKAGE) { + switch (topology[i].data.package.vendor) { + case B_CPU_VENDOR_INTEL: + logo = IntelLogo; + break; + + case B_CPU_VENDOR_AMD: + logo = AmdLogo; + break; + + default: + break; + } + + break; + } + } + + delete[] topology; #endif fCpuLogo->SetBits(logo, fCpuLogo->BitsLength(), 0, B_CMAP8); @@ -255,9 +273,8 @@ NormalPulseView::AttachedToWindow() system_info sys_info; get_system_info(&sys_info); if (sys_info.cpu_count >= 2) { - for (int x = 0; x < sys_info.cpu_count; x++) { + for (unsigned int x = 0; x < sys_info.cpu_count; x++) cpu_menu_items[x]->SetTarget(messenger); - } } } @@ -270,7 +287,7 @@ NormalPulseView::UpdateColors(BMessage *message) system_info sys_info; get_system_info(&sys_info); - for (int x = 0; x < sys_info.cpu_count; x++) { + for (unsigned int x = 0; x < sys_info.cpu_count; x++) { fProgressBars[x]->UpdateColors(color, fade); fCpuButtons[x]->UpdateColors(color); } diff --git a/src/apps/pulse/PulseApp.cpp b/src/apps/pulse/PulseApp.cpp index 659762c2ba..af2f6f471b 100644 --- a/src/apps/pulse/PulseApp.cpp +++ b/src/apps/pulse/PulseApp.cpp @@ -207,14 +207,14 @@ PulseApp::ShowAbout(bool asApplication) */ bool -LastEnabledCPU(int my_cpu) +LastEnabledCPU(unsigned int my_cpu) { system_info sys_info; get_system_info(&sys_info); if (sys_info.cpu_count == 1) return true; - for (int x = 0; x < sys_info.cpu_count; x++) { + for (unsigned int x = 0; x < sys_info.cpu_count; x++) { if (x == my_cpu) continue; if (_kern_cpu_enabled(x) == 1) diff --git a/src/apps/pulse/PulseApp.h b/src/apps/pulse/PulseApp.h index d51cd3f344..266af30d4f 100644 --- a/src/apps/pulse/PulseApp.h +++ b/src/apps/pulse/PulseApp.h @@ -32,7 +32,7 @@ private: void BuildPulse(); }; -extern bool LastEnabledCPU(int cpu); +extern bool LastEnabledCPU(unsigned int cpu); extern int GetMinimumViewWidth(); extern bool LoadInDeskbar(); extern void Usage(); diff --git a/src/apps/pulse/PulseView.cpp b/src/apps/pulse/PulseView.cpp index bc5969a0af..b4ebb8d9a6 100644 --- a/src/apps/pulse/PulseView.cpp +++ b/src/apps/pulse/PulseView.cpp @@ -26,8 +26,14 @@ #define B_TRANSLATION_CONTEXT "PulseView" -PulseView::PulseView(BRect rect, const char *name) : - BView(rect, name, B_FOLLOW_ALL_SIDES, B_WILL_DRAW | B_PULSE_NEEDED | B_FRAME_EVENTS) { +PulseView::PulseView(BRect rect, const char *name) + : + BView(rect, name, B_FOLLOW_ALL_SIDES, + B_WILL_DRAW | B_PULSE_NEEDED | B_FRAME_EVENTS), + kCPUCount(sysconf(_SC_NPROCESSORS_CONF)), + cpu_times(new double[kCPUCount]), + prev_active(new bigtime_t[kCPUCount]) +{ popupmenu = NULL; cpu_menu_items = NULL; @@ -40,7 +46,13 @@ PulseView::PulseView(BRect rect, const char *name) : } // This version will be used by the instantiated replicant -PulseView::PulseView(BMessage *message) : BView(message) { +PulseView::PulseView(BMessage *message) + : + BView(message), + kCPUCount(sysconf(_SC_NPROCESSORS_CONF)), + cpu_times(new double[kCPUCount]), + prev_active(new bigtime_t[kCPUCount]) +{ SetResizingMode(B_FOLLOW_ALL_SIDES); SetFlags(B_WILL_DRAW | B_PULSE_NEEDED); @@ -50,6 +62,9 @@ PulseView::PulseView(BMessage *message) : BView(message) { } void PulseView::Init() { + memset(cpu_times, 0, sizeof(double) * kCPUCount); + memset(prev_active, 0, sizeof(double) * kCPUCount); + popupmenu = new BPopUpMenu("PopUpMenu", false, false, B_ITEMS_IN_COLUMN); popupmenu->SetFont(be_plain_font); mode1 = new BMenuItem("", NULL, 0, 0); @@ -70,7 +85,7 @@ void PulseView::Init() { if (sys_info.cpu_count >= 2) { cpu_menu_items = new BMenuItem *[sys_info.cpu_count]; char temp[20]; - for (int x = 0; x < sys_info.cpu_count; x++) { + for (unsigned int x = 0; x < sys_info.cpu_count; x++) { sprintf(temp, "CPU %d", x + 1); BMessage *message = new BMessage(PV_CPU_MENU_ITEM); message->AddInt32("which", x); @@ -103,10 +118,14 @@ void PulseView::Update() { get_system_info(&sys_info); bigtime_t now = system_time(); + cpu_info* cpuInfos = new cpu_info[sys_info.cpu_count]; + get_cpu_info(0, sys_info.cpu_count, cpuInfos); + // Calculate work done since last call to Update() for each CPU - for (int x = 0; x < sys_info.cpu_count; x++) { - double cpu_time = (double)(sys_info.cpu_infos[x].active_time - prev_active[x]) / (now - prev_time); - prev_active[x] = sys_info.cpu_infos[x].active_time; + for (unsigned int x = 0; x < sys_info.cpu_count; x++) { + double cpu_time = (double)(cpuInfos[x].active_time - prev_active[x]) + / (now - prev_time); + prev_active[x] = cpuInfos[x].active_time; if (cpu_time < 0) cpu_time = 0; if (cpu_time > 1) cpu_time = 1; cpu_times[x] = cpu_time; @@ -119,6 +138,8 @@ void PulseView::Update() { } } prev_time = now; + + delete[] cpuInfos; } void PulseView::ChangeCPUState(BMessage *message) { @@ -138,5 +159,8 @@ void PulseView::ChangeCPUState(BMessage *message) { PulseView::~PulseView() { if (popupmenu != NULL) delete popupmenu; if (cpu_menu_items != NULL) delete cpu_menu_items; + + delete[] prev_active; + delete[] cpu_times; } diff --git a/src/apps/pulse/PulseView.h b/src/apps/pulse/PulseView.h index b61922a886..d6e0f9f4d6 100644 --- a/src/apps/pulse/PulseView.h +++ b/src/apps/pulse/PulseView.h @@ -32,8 +32,10 @@ class PulseView : public BView { BMenuItem *mode1, *mode2, *preferences, *about; BMenuItem **cpu_menu_items; - double cpu_times[B_MAX_CPU_COUNT]; - bigtime_t prev_active[B_MAX_CPU_COUNT]; + const int32 kCPUCount; + + double* cpu_times; + bigtime_t* prev_active; bigtime_t prev_time; }; diff --git a/src/apps/showimage/Filter.h b/src/apps/showimage/Filter.h index 8021ca133f..7b410ebf0e 100644 --- a/src/apps/showimage/Filter.h +++ b/src/apps/showimage/Filter.h @@ -149,7 +149,7 @@ private: bool fStarted; // has Start() been called? sem_id fWaitForThreads; // to exit int32 fN; // the number of used filter threads - volatile int32 fNumberOfThreads; // the current number of FilterThreads + int32 fNumberOfThreads; // the current number of FilterThreads volatile bool fIsRunning; // FilterThreads should process data as long as it is true BBitmap* fSrcImage; bool fDestImageInitialized; diff --git a/src/apps/showimage/ImageCache.h b/src/apps/showimage/ImageCache.h index 000fa95ff2..ac572c02fa 100644 --- a/src/apps/showimage/ImageCache.h +++ b/src/apps/showimage/ImageCache.h @@ -86,7 +86,7 @@ private: CacheList fCacheEntriesByAge; QueueMap fQueueMap; QueueDeque fQueue; - vint32 fThreadCount; + int32 fThreadCount; int32 fMaxThreadCount; uint64 fBytes; uint64 fMaxBytes; diff --git a/src/apps/terminal/TermParse.cpp b/src/apps/terminal/TermParse.cpp index b86fbe52f3..d22ef38154 100644 --- a/src/apps/terminal/TermParse.cpp +++ b/src/apps/terminal/TermParse.cpp @@ -1205,9 +1205,9 @@ TermParse::_ReadParserBuffer() fBuffer->Unlock(); // wait for new input from pty - if (fReadBufferSize == 0) { + if (atomic_get(&fReadBufferSize) == 0) { status_t status = B_OK; - while (fReadBufferSize == 0 && status == B_OK) { + while (atomic_get(&fReadBufferSize) == 0 && status == B_OK) { do { status = acquire_sem(fReaderSem); } while (status == B_INTERRUPTED); @@ -1224,7 +1224,7 @@ TermParse::_ReadParserBuffer() } } - int32 toRead = fReadBufferSize; + int32 toRead = atomic_get(&fReadBufferSize); if (toRead > ESC_PARSER_BUFFER_SIZE) toRead = ESC_PARSER_BUFFER_SIZE; diff --git a/src/apps/terminal/TermParse.h b/src/apps/terminal/TermParse.h index a9aeb8dacd..26e57ecc78 100644 --- a/src/apps/terminal/TermParse.h +++ b/src/apps/terminal/TermParse.h @@ -73,7 +73,7 @@ private: uint fBufferPosition; uchar fReadBuffer[READ_BUF_SIZE]; - vint32 fReadBufferSize; + int32 fReadBufferSize; uchar fParserBuffer[ESC_PARSER_BUFFER_SIZE]; int32 fParserBufferSize; diff --git a/src/bin/Jamfile b/src/bin/Jamfile index 69357ca3fb..0870e77435 100644 --- a/src/bin/Jamfile +++ b/src/bin/Jamfile @@ -49,7 +49,6 @@ StdBinCommands release.c renice.c rescan.c - sysinfo.cpp unchop.c uptime.cpp vmstat.cpp @@ -167,6 +166,7 @@ StdBinCommands # commands that need libstdc++ only StdBinCommands diff_zip.cpp + sysinfo.cpp : $(TARGET_LIBSTDC++) : $(haiku-utils_rsrc) ; # standard commands that need libbe.so, libtranslation.so, libsupc++.so diff --git a/src/bin/coreutils/src/uname.c b/src/bin/coreutils/src/uname.c index 16b0b33c94..1bf091458c 100644 --- a/src/bin/coreutils/src/uname.c +++ b/src/bin/coreutils/src/uname.c @@ -346,16 +346,20 @@ main (int argc, char **argv) #ifdef __HAIKU__ { - system_info sysinfo; - get_system_info(&sysinfo); - - switch (sysinfo.platform_type) { - case B_AT_CLONE_PLATFORM: - element = "x86"; - break; - case B_64_BIT_PC_PLATFORM: - element = "x86_64"; - break; + cpu_topology_node_info root; + uint32_t count = 1; + status_t error = get_cpu_topology_info(&root, &count); + if (error != B_OK || count < 1) + element = "unknown"; + else { + switch (root.data.root.platform) { + case B_CPU_x86: + element = "x86"; + break; + case B_CPU_x86_64: + element = "x86_64"; + break; + } } } #endif diff --git a/src/bin/sysinfo.cpp b/src/bin/sysinfo.cpp index 2b096d9a13..1429c2260f 100644 --- a/src/bin/sysinfo.cpp +++ b/src/bin/sysinfo.cpp @@ -141,7 +141,8 @@ struct cache_description { static void -print_intel_cache_descriptors(enum cpu_types type, cpuid_info *info) +print_intel_cache_descriptors(enum cpu_vendor vendor, uint32 model, + cpuid_info *info) { uint8 cacheDescriptors[15]; // Max @@ -195,9 +196,8 @@ print_intel_cache_descriptors(enum cpu_types type, cpuid_info *info) if (cacheDescriptors[i] == sIntelCacheDescriptions[j].code) { if (cacheDescriptors[i] == 0x40) { printf("\tNo integrated L%u cache\n", - type >= B_CPU_INTEL_PENTIUM_IV - && (type & B_CPU_x86_VENDOR_MASK) == B_CPU_INTEL_x86 - ? 3 : 2); + ((model >> 8) & 0xf) == 0xf + && vendor == B_CPU_VENDOR_INTEL ? 3 : 2); } else printf("\t%s\n", sIntelCacheDescriptions[j].description); break; @@ -210,6 +210,7 @@ print_intel_cache_descriptors(enum cpu_types type, cpuid_info *info) } } + #endif // __INTEL__ || __x86_64__ @@ -466,12 +467,11 @@ print_features(uint32 features) #if defined(__INTEL__) || defined(__x86_64__) static void -print_processor_signature(system_info *sys_info, cpuid_info *info, +print_processor_signature(enum cpu_vendor vendor, cpuid_info *info, const char *prefix) { - if ((sys_info->cpu_type & B_CPU_x86_VENDOR_MASK) == B_CPU_AMD_x86) { - + if (vendor == B_CPU_VENDOR_AMD) { printf("\t%s%sype %" B_PRIu32 ", family %" B_PRIu32 ", model %" B_PRIu32 ", stepping %" B_PRIu32 ", features 0x%08" B_PRIx32 "\n", prefix ? prefix : "", prefix && prefix[0] ? "t" : "T", @@ -482,8 +482,7 @@ print_processor_signature(system_info *sys_info, cpuid_info *info, ? info->eax_1.extended_model << 4 : 0), info->eax_1.stepping, info->eax_1.features); - } else if ((sys_info->cpu_type & B_CPU_x86_VENDOR_MASK) - == B_CPU_INTEL_x86) { + } else if (vendor == B_CPU_VENDOR_INTEL) { // model calculation is different for INTEL printf("\t%s%sype %" B_PRIu32 ", family %" B_PRIu32 ", model %" B_PRIu32 ", stepping %" B_PRIu32 ", features 0x%08" B_PRIx32 "\n", @@ -505,17 +504,33 @@ print_processor_signature(system_info *sys_info, cpuid_info *info, static void dump_platform(system_info *info) { - printf("%s\n", - info->platform_type == B_AT_CLONE_PLATFORM ? "IntelArchitecture" : - info->platform_type == B_MAC_PLATFORM ? "Macintosh" : - info->platform_type == B_BEBOX_PLATFORM ? "BeBox" : "unknown"); + cpu_topology_node_info root; + uint32 count = 1; + get_cpu_topology_info(&root, &count); + + const char* platform; + switch (root.data.root.platform) { + case B_CPU_x86: + platform = "IntelArchitecture"; + break; + + case B_CPU_x86_64: + platform = "IntelArchitecture (64 bit)"; + break; + + default: + platform = "unknown"; + break; + } + + printf("%s\n", platform); } #if defined(__INTEL__) || defined(__x86_64__) static void -dump_cpu(system_info *info, int32 cpu) +dump_cpu(enum cpu_vendor vendor, uint32 model, int32 cpu) { // References: // http://grafi.ii.pw.edu.pl/gbm/x86/cpuid.html @@ -573,7 +588,7 @@ dump_cpu(system_info *info, int32 cpu) else { // Intel CPUs don't seem to have the genuine vendor field printf("CPU #%" B_PRId32 ": %.12s\n", cpu, - (info->cpu_type & B_CPU_x86_VENDOR_MASK) == B_CPU_INTEL_x86 ? + vendor == B_CPU_VENDOR_INTEL ? baseInfo.eax_0.vendor_id : cpuInfo.eax_0.vendor_id); } } else { @@ -583,31 +598,13 @@ dump_cpu(system_info *info, int32 cpu) } get_cpuid(&cpuInfo, 1, cpu); - // Dump Raw CPUID, and internal CPUID we use... + // Dump Raw CPUID printf("\tRaw CPUID: 0x%1" B_PRIx32 "%1" B_PRIx32 "0%1" B_PRIx32 "%1" B_PRIx32 "%1" B_PRIx32 ", ", cpuInfo.eax_1.extended_family, cpuInfo.eax_1.extended_model, cpuInfo.eax_1.family, cpuInfo.eax_1.model, cpuInfo.eax_1.stepping); - // This logic should be kept in-sync with x86/arch_system_info.cpp - // There is also src/tools/cpuidtool.cpp to do command line conversions - // of CPUID's to OS.h CPUID's - uint32 internalCPUID = 0; - if (((info->cpu_type & B_CPU_x86_VENDOR_MASK) == B_CPU_AMD_x86 - && cpuInfo.eax_1.family == 0xF) - || (info->cpu_type & B_CPU_x86_VENDOR_MASK) == B_CPU_INTEL_x86) { - internalCPUID = (cpuInfo.eax_1.extended_family << 20) - + (cpuInfo.eax_1.extended_model << 16) - + (cpuInfo.eax_1.family << 4) + cpuInfo.eax_1.model; - } else - internalCPUID = (cpuInfo.eax_1.family << 4) + cpuInfo.eax_1.model; - - internalCPUID += info->cpu_type & B_CPU_x86_VENDOR_MASK; - - // Matches OS.h define - printf("Haiku Internal ID (OS.h): 0x%" B_PRIx32 "\n", internalCPUID); - - print_processor_signature(info, &cpuInfo, NULL); + print_processor_signature(vendor, &cpuInfo, NULL); print_features(cpuInfo.eax_1.features); if (maxStandardFunction >= 1) { @@ -619,17 +616,15 @@ dump_cpu(system_info *info, int32 cpu) /* Extended CPUID */ if (maxExtendedFunction >= 1) { get_cpuid(&cpuInfo, 0x80000001, cpu); - print_processor_signature(info, &cpuInfo, "Extended AMD: "); + print_processor_signature(vendor, &cpuInfo, "Extended AMD: "); - if ((info->cpu_type & B_CPU_x86_VENDOR_MASK) == B_CPU_AMD_x86 - || (info->cpu_type & B_CPU_x86_VENDOR_MASK) == B_CPU_INTEL_x86) { + if (vendor == B_CPU_VENDOR_AMD || vendor == B_CPU_VENDOR_INTEL) { print_amd_features(cpuInfo.regs.edx); if (maxExtendedFunction >= 7) { get_cpuid(&cpuInfo, 0x80000007, cpu); print_amd_power_management_features(cpuInfo.regs.edx); } - } else if ((info->cpu_type & B_CPU_x86_VENDOR_MASK) - == B_CPU_TRANSMETA_x86) + } else if (vendor == B_CPU_VENDOR_TRANSMETA) print_transmeta_features(cpuInfo.regs.edx); } @@ -637,9 +632,8 @@ dump_cpu(system_info *info, int32 cpu) if (maxExtendedFunction >= 5) { if (!strncmp(baseInfo.eax_0.vendor_id, "CyrixInstead", 12)) { get_cpuid(&cpuInfo, 0x00000002, cpu); - print_intel_cache_descriptors(info->cpu_type, &cpuInfo); - } else if ((info->cpu_type & B_CPU_x86_VENDOR_MASK) - == B_CPU_INTEL_x86) { + print_intel_cache_descriptors(vendor, model, &cpuInfo); + } else if (vendor == B_CPU_VENDOR_INTEL) { // Intel does not support extended function 5 (but it does 6 hmm) print_intel_cache_desc(cpu); } else { @@ -652,7 +646,7 @@ dump_cpu(system_info *info, int32 cpu) get_cpuid(&cpuInfo, 2, cpu); if (cpuInfo.eax_2.call_num > 0) - print_intel_cache_descriptors(info->cpu_type, &cpuInfo); + print_intel_cache_descriptors(vendor, model, &cpuInfo); } while (cpuInfo.eax_2.call_num > 1); } @@ -681,28 +675,59 @@ dump_cpu(system_info *info, int32 cpu) static void dump_cpus(system_info *info) { - const char *vendor = get_cpu_vendor_string(info->cpu_type); - const char *model = get_cpu_model_string(info); + uint32 topologyNodeCount = 0; + cpu_topology_node_info* topology = NULL; + get_cpu_topology_info(NULL, &topologyNodeCount); + if (topologyNodeCount != 0) + topology = new cpu_topology_node_info[topologyNodeCount]; + get_cpu_topology_info(topology, &topologyNodeCount); + + enum cpu_platform platform = B_CPU_UNKNOWN; + enum cpu_vendor cpuVendor = B_CPU_VENDOR_UNKNOWN; + uint32 cpuModel = 0; + uint64 frequency = 0; + for (uint32 i = 0; i < topologyNodeCount; i++) { + switch (topology[i].type) { + case B_TOPOLOGY_ROOT: + platform = topology[i].data.root.platform; + break; + + case B_TOPOLOGY_PACKAGE: + cpuVendor = topology[i].data.package.vendor; + break; + + case B_TOPOLOGY_CORE: + cpuModel = topology[i].data.core.model; + frequency = topology[i].data.core.default_frequency; + break; + + default: + break; + } + } + delete[] topology; + + const char *vendor = get_cpu_vendor_string(cpuVendor); + const char *model = get_cpu_model_string(platform, cpuVendor, cpuModel); char modelString[32]; if (model == NULL && vendor == NULL) model = "(Unknown)"; else if (model == NULL) { model = modelString; - snprintf(modelString, 32, "(Unknown %x)", info->cpu_type); + snprintf(modelString, 32, "(Unknown %" B_PRIx32 ")", cpuModel); } printf("%" B_PRId32 " %s%s%s, revision %04" B_PRIx32 " running at %" - B_PRId64 "MHz (ID: 0x%08" B_PRIx32 " 0x%08" B_PRIx32 ")\n\n", + B_PRIu64 "MHz\n\n", info->cpu_count, vendor ? vendor : "", vendor ? " " : "", model, - info->cpu_revision, - info->cpu_clock_speed / 1000000, - info->id[0], info->id[1]); + cpuModel, + frequency / 1000000); #if defined(__INTEL__) || defined(__x86_64__) - for (int32 cpu = 0; cpu < info->cpu_count; cpu++) - dump_cpu(info, cpu); + for (uint32 cpu = 0; cpu < info->cpu_count; cpu++) + dump_cpu(cpuVendor, cpuModel, cpu); #endif // __INTEL__ || __x86_64__ } @@ -804,8 +829,7 @@ main(int argc, char *argv[]) const char *opt = argv[i]; if (strncmp(opt, "-id", strlen(opt)) == 0) { /* note: the original also assumes this option on "sysinfo -" */ - printf("0x%.8" B_PRIx32 " 0x%.8" B_PRIx32 "\n", info.id[0], - info.id[1]); + printf("%#.8x %#.8x\n", 0,0); } else if (strncmp(opt, "-cpu", strlen(opt)) == 0) { dump_cpus(&info); } else if (strncmp(opt, "-mem", strlen(opt)) == 0) { diff --git a/src/bin/top.c b/src/bin/top.c index d7d79e42aa..4dff9601a3 100644 --- a/src/bin/top.c +++ b/src/bin/top.c @@ -179,8 +179,6 @@ static void compare( thread_time_list_t *old, thread_time_list_t *new, - bigtime_t old_busy, - bigtime_t new_busy, bigtime_t uinterval, int refresh ) @@ -263,7 +261,7 @@ compare( printf("%6s %7s %7s %7s %4s %16s %-16s \n", "THID", "TOTAL", "USER", "KERNEL", "%CPU", "TEAM NAME", "THREAD NAME"); linecount = 1; - idletime = new_busy - old_busy; + idletime = 0; gtotal = 0; ktotal = 0; utotal = 0; @@ -354,7 +352,6 @@ adjust_term(bool onlyRows) static thread_time_list_t gather( thread_time_list_t *old, - bigtime_t *busy_wait_time, int refresh ) { @@ -363,7 +360,6 @@ gather( thread_info t; team_info tm; thread_time_list_t times; - bigtime_t old_busy; int i; system_info info; bigtime_t oldLastMeasure; @@ -374,10 +370,6 @@ gather( oldLastMeasure = lastMeasure; lastMeasure = system_time(); - get_system_info(&info); - old_busy = *busy_wait_time; - *busy_wait_time = info._busy_wait_time; - while (get_next_team_info(&tmcookie, &tm) == B_NO_ERROR) { thcookie = 0; while (get_next_thread_info(tm.team, &thcookie, &t) == B_NO_ERROR) { @@ -393,8 +385,7 @@ gather( adjust_term(true); screen_size_changed = 0; } - compare(old, ×, old_busy, *busy_wait_time, - system_time() - oldLastMeasure, refresh); + compare(old, ×, system_time() - oldLastMeasure, refresh); free_times(old); } return (times); @@ -432,7 +423,6 @@ main(int argc, char **argv) //bigtime_t then; bigtime_t uinterval; bigtime_t elapsed; - bigtime_t busy; char *myname; get_system_info (&sysinfo); @@ -482,22 +472,22 @@ main(int argc, char **argv) if (iters < 0) { // You will only have to wait half a second for the first iteration. uinterval = 1 * 1000000 / 2; - baseline = gather(NULL, &busy, refresh); + baseline = gather(NULL, refresh); elapsed = system_time() - lastMeasure; if (elapsed < uinterval) snooze(uinterval - elapsed); // then = system_time(); - baseline = gather(&baseline, &busy, refresh); + baseline = gather(&baseline, refresh); } else - baseline = gather(NULL, &busy, refresh); + baseline = gather(NULL, refresh); uinterval = interval * 1000000; for (i = 0; iters < 0 || i < iters; i++) { elapsed = system_time() - lastMeasure; if (elapsed < uinterval) snooze(uinterval - elapsed); - baseline = gather(&baseline, &busy, refresh); + baseline = gather(&baseline, refresh); } printf(exit_ca_mode); diff --git a/src/bin/vmstat.cpp b/src/bin/vmstat.cpp index ed2dee580f..9d6085b32f 100644 --- a/src/bin/vmstat.cpp +++ b/src/bin/vmstat.cpp @@ -66,40 +66,44 @@ main(int argc, char** argv) break; } } - system_memory_info info; - status_t status = __get_system_info_etc(B_MEMORY_INFO, &info, - sizeof(system_memory_info)); + system_info info; + status_t status = get_system_info(&info); if (status != B_OK) { fprintf(stderr, "%s: cannot get system info: %s\n", kProgramName, strerror(status)); return 1; } - printf("max memory:\t\t%Lu\n", info.max_memory); + printf("max memory:\t\t%Lu\n", info.max_pages * B_PAGE_SIZE); printf("free memory:\t\t%Lu\n", info.free_memory); printf("needed memory:\t\t%Lu\n", info.needed_memory); - printf("block cache memory:\t%Lu\n", info.block_cache_memory); - printf("max swap space:\t\t%Lu\n", info.max_swap_space); - printf("free swap space:\t%Lu\n", info.free_swap_space); + printf("block cache memory:\t%Lu\n", info.block_cache_pages * B_PAGE_SIZE); + printf("max swap space:\t\t%Lu\n", info.max_swap_pages * B_PAGE_SIZE); + printf("free swap space:\t%Lu\n", info.free_swap_pages * B_PAGE_SIZE); printf("page faults:\t\t%lu\n", info.page_faults); if (periodically) { puts("\npage faults used memory used swap block cache"); - system_memory_info lastInfo = info; + system_info lastInfo = info; while (true) { snooze(rate); - __get_system_info_etc(B_MEMORY_INFO, &info, - sizeof(system_memory_info)); + get_system_info(&info); - printf("%11ld %11Ld %11Ld %11Ld\n", - (int32)info.page_faults - lastInfo.page_faults, - (info.max_memory - info.free_memory) - - (lastInfo.max_memory - lastInfo.free_memory), - (info.max_swap_space - info.free_swap_space) - - (lastInfo.max_swap_space - lastInfo.free_swap_space), - info.block_cache_memory - lastInfo.block_cache_memory); + int32 pageFaults = info.page_faults - lastInfo.page_faults; + int64 usedMemory + = (info.max_pages * B_PAGE_SIZE - info.free_memory) + - (lastInfo.max_pages * B_PAGE_SIZE - lastInfo.free_memory); + int64 usedSwap + = ((info.max_swap_pages - info.free_swap_pages) + - (lastInfo.max_swap_pages - lastInfo.free_swap_pages)) + * B_PAGE_SIZE; + int64 blockCache + = (info.block_cache_pages - lastInfo.block_cache_pages) + * B_PAGE_SIZE; + printf("%11" B_PRId32 " %11" B_PRId64 " %11" B_PRId64 " %11" + B_PRId64 "\n", pageFaults, usedMemory, usedSwap, blockCache); lastInfo = info; } diff --git a/src/build/libroot/atomic.cpp b/src/build/libroot/atomic.cpp index f7a726915a..38aed02692 100644 --- a/src/build/libroot/atomic.cpp +++ b/src/build/libroot/atomic.cpp @@ -6,8 +6,15 @@ #include +void +atomic_set(int32 *value, int32 newValue) +{ + *value = newValue; +} + + int32 -atomic_set(vint32 *value, int32 newValue) +atomic_get_and_set(int32 *value, int32 newValue) { int32 oldValue = *value; *value = newValue; @@ -16,7 +23,7 @@ atomic_set(vint32 *value, int32 newValue) int32 -atomic_test_and_set(vint32 *value, int32 newValue, int32 testAgainst) +atomic_test_and_set(int32 *value, int32 newValue, int32 testAgainst) { int32 oldValue = *value; if (oldValue == testAgainst) @@ -26,7 +33,7 @@ atomic_test_and_set(vint32 *value, int32 newValue, int32 testAgainst) int32 -atomic_add(vint32 *value, int32 addValue) +atomic_add(int32 *value, int32 addValue) { int32 oldValue = *value; *value += addValue; @@ -35,7 +42,7 @@ atomic_add(vint32 *value, int32 addValue) int32 -atomic_and(vint32 *value, int32 andValue) +atomic_and(int32 *value, int32 andValue) { int32 oldValue = *value; *value &= andValue; @@ -44,7 +51,7 @@ atomic_and(vint32 *value, int32 andValue) int32 -atomic_or(vint32 *value, int32 orValue) +atomic_or(int32 *value, int32 orValue) { int32 oldValue = *value; *value |= orValue; @@ -53,14 +60,21 @@ atomic_or(vint32 *value, int32 orValue) int32 -atomic_get(vint32 *value) +atomic_get(int32 *value) { return *value; } +void +atomic_set64(int64 *value, int64 newValue) +{ + *value = newValue; +} + + int64 -atomic_set64(vint64 *value, int64 newValue) +atomic_get_and_set64(int64 *value, int64 newValue) { int64 oldValue = *value; *value = newValue; @@ -68,7 +82,7 @@ atomic_set64(vint64 *value, int64 newValue) } int64 -atomic_test_and_set64(vint64 *value, int64 newValue, int64 testAgainst) +atomic_test_and_set64(int64 *value, int64 newValue, int64 testAgainst) { int64 oldValue = *value; if (oldValue == testAgainst) @@ -77,7 +91,7 @@ atomic_test_and_set64(vint64 *value, int64 newValue, int64 testAgainst) } int64 -atomic_add64(vint64 *value, int64 addValue) +atomic_add64(int64 *value, int64 addValue) { int64 oldValue = *value; *value += addValue; @@ -85,7 +99,7 @@ atomic_add64(vint64 *value, int64 addValue) } int64 -atomic_and64(vint64 *value, int64 andValue) +atomic_and64(int64 *value, int64 andValue) { int64 oldValue = *value; *value &= andValue; @@ -93,7 +107,7 @@ atomic_and64(vint64 *value, int64 andValue) } int64 -atomic_or64(vint64 *value, int64 orValue) +atomic_or64(int64 *value, int64 orValue) { int64 oldValue = *value; *value |= orValue; @@ -101,7 +115,7 @@ atomic_or64(vint64 *value, int64 orValue) } int64 -atomic_get64(vint64 *value) +atomic_get64(int64 *value) { return *value; } diff --git a/src/kits/media/MediaRoster.cpp b/src/kits/media/MediaRoster.cpp index 4b13a37d85..064a2297b8 100644 --- a/src/kits/media/MediaRoster.cpp +++ b/src/kits/media/MediaRoster.cpp @@ -3126,25 +3126,10 @@ BMediaRoster::AudioBufferSizeFor(int32 channelCount, uint32 sampleFormat, bigtime_t bufferDuration; ssize_t bufferSize; - system_info info; - get_system_info(&info); - - if (info.cpu_clock_speed > 2000000000) // 2 GHz - bufferDuration = 2500; - else if (info.cpu_clock_speed > 1000000000) - bufferDuration = 5000; - else if (info.cpu_clock_speed > 600000000) - bufferDuration = 10000; - else if (info.cpu_clock_speed > 200000000) - bufferDuration = 20000; - else if (info.cpu_clock_speed > 100000000) - bufferDuration = 30000; - else - bufferDuration = 50000; - - if ((busKind == B_ISA_BUS || busKind == B_PCMCIA_BUS) - && bufferDuration < 25000) + if (busKind == B_ISA_BUS || busKind == B_PCMCIA_BUS) bufferDuration = 25000; + else + bufferDuration = 10000; bufferSize = (sampleFormat & 0xf) * channelCount * (ssize_t)((frameRate * bufferDuration) / 1000000.0); diff --git a/src/kits/storage/mime/MimeSnifferAddonManager.cpp b/src/kits/storage/mime/MimeSnifferAddonManager.cpp index 58272fc8b7..fcdb7e9914 100644 --- a/src/kits/storage/mime/MimeSnifferAddonManager.cpp +++ b/src/kits/storage/mime/MimeSnifferAddonManager.cpp @@ -54,7 +54,7 @@ struct MimeSnifferAddonManager::AddonReference { private: BMimeSnifferAddon* fAddon; - vint32 fReferenceCount; + int32 fReferenceCount; }; diff --git a/src/kits/support/String.cpp b/src/kits/support/String.cpp index 56b6084e93..b5cfaafef4 100644 --- a/src/kits/support/String.cpp +++ b/src/kits/support/String.cpp @@ -183,14 +183,14 @@ BStringRef::operator&() // #pragma mark - BString -inline vint32& +inline int32& BString::_ReferenceCount() { return Private::DataRefCount(fPrivateData); } -inline const vint32& +inline const int32& BString::_ReferenceCount() const { return Private::DataRefCount(fPrivateData); diff --git a/src/kits/tracker/TaskLoop.cpp b/src/kits/tracker/TaskLoop.cpp index 6a3b00ed95..c87fdc310f 100644 --- a/src/kits/tracker/TaskLoop.cpp +++ b/src/kits/tracker/TaskLoop.cpp @@ -172,8 +172,14 @@ ActivityLevel() bigtime_t time = 0; system_info sinfo; get_system_info(&sinfo); - for (int32 index = 0; index < sinfo.cpu_count; index++) - time += sinfo.cpu_infos[index].active_time; + + cpu_info* cpuInfos = new cpu_info[sinfo.cpu_count]; + get_cpu_info(0, sinfo.cpu_count, cpuInfos); + + for (uint32 index = 0; index < sinfo.cpu_count; index++) + time += cpuInfos[index].active_time; + + delete[] cpuInfos; return time / ((bigtime_t) sinfo.cpu_count); } diff --git a/src/libs/compat/freebsd_network/Condvar.cpp b/src/libs/compat/freebsd_network/Condvar.cpp index 74499ef0cb..9cb5be1dcd 100644 --- a/src/libs/compat/freebsd_network/Condvar.cpp +++ b/src/libs/compat/freebsd_network/Condvar.cpp @@ -77,5 +77,5 @@ publishedConditionTimedWait(const void* waitChannel, const int timeout) void publishedConditionNotifyAll(const void* waitChannel) { - ConditionVariable::NotifyAll(waitChannel); + ConditionVariable::NotifyAll(waitChannel, B_OK); } diff --git a/src/libs/compat/freebsd_wlan/net80211/ieee80211_haiku.cpp b/src/libs/compat/freebsd_wlan/net80211/ieee80211_haiku.cpp index b1f936febb..e0398ffa5b 100644 --- a/src/libs/compat/freebsd_wlan/net80211/ieee80211_haiku.cpp +++ b/src/libs/compat/freebsd_wlan/net80211/ieee80211_haiku.cpp @@ -463,7 +463,7 @@ int ieee80211_node_dectestref(struct ieee80211_node* ni) { // atomic_add returns old value - return atomic_add((vint32*)&ni->ni_refcnt, -1) == 1; + return atomic_add((int32*)&ni->ni_refcnt, -1) == 1; } diff --git a/src/preferences/Jamfile b/src/preferences/Jamfile index 99c59fb3c8..05a3858233 100644 --- a/src/preferences/Jamfile +++ b/src/preferences/Jamfile @@ -3,7 +3,6 @@ SubDir HAIKU_TOP src preferences ; SubInclude HAIKU_TOP src preferences appearance ; SubInclude HAIKU_TOP src preferences backgrounds ; SubInclude HAIKU_TOP src preferences bluetooth ; -SubInclude HAIKU_TOP src preferences cpufrequency ; SubInclude HAIKU_TOP src preferences datatranslations ; SubInclude HAIKU_TOP src preferences deskbar ; #SubInclude HAIKU_TOP src preferences dun ; diff --git a/src/preferences/cpufrequency/CPUFrequencyView.cpp b/src/preferences/cpufrequency/CPUFrequencyView.cpp deleted file mode 100644 index b0e1adf6c2..0000000000 --- a/src/preferences/cpufrequency/CPUFrequencyView.cpp +++ /dev/null @@ -1,252 +0,0 @@ -/* - * Copyright 2009-2010, Haiku, Inc. All Rights Reserved. - * Distributed under the terms of the MIT License. - * - * Authors: - * Clemens Zeidler, haiku@clemens-zeidler.de - */ - - -#include "CPUFrequencyView.h" - -#include "StatusView.h" - -#include -#include -#include -#include -#include -#include -#include - - -#undef B_TRANSLATION_CONTEXT -#define B_TRANSLATION_CONTEXT "CPU Frequency View" - - -const char* kCPUFreqPreferencesFile = "CPUFrequency"; -const char* kPrefSignature = "application/x-vnd.Haiku-CPUFrequencyPref"; -const char* kPreferencesFileName = "CPUFrequency"; - -const uint32 kInstallIntoDeskbar = '&iid'; -const uint32 kIntegrationTimeChanged = '&itc'; - -const bigtime_t kMilliSecond = 1000; - - -CPUFrequencyView::CPUFrequencyView(BRect frame, - PreferencesStorage* storage) - : - BView(frame, "CPUFrequencyView", B_FOLLOW_NONE, B_WILL_DRAW), - fStorage(storage) -{ - BGroupLayout* mainLayout = new BGroupLayout(B_VERTICAL); - SetLayout(mainLayout); - mainLayout->SetSpacing(10); - SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); - - // stepping policy - BRect rect = Bounds(); - rect.InsetBy(5, 5); - BBox *policyBox = new BBox(rect, "policyBox"); - policyBox->SetLabel(B_TRANSLATE("Stepping policy")); - BGroupLayout* policyLayout = new BGroupLayout(B_VERTICAL); - policyLayout->SetInsets(10, policyBox->TopBorderOffset() * 2 + 10, 10, 10); - policyLayout->SetSpacing(10); - policyBox->SetLayout(policyLayout); - mainLayout->AddView(policyBox); - - fPolicyMenu = new BMenu(B_TRANSLATE("Stepping policy: ")); - BMenuField *menuField = new BMenuField("", fPolicyMenu); - policyLayout->AddView(menuField); - - // dynamic stepping - BBox *dynamicBox = new BBox(rect, "dynamicBox"); - dynamicBox->SetLabel(B_TRANSLATE("Dynamic stepping")); - BGroupLayout* dynamicLayout = new BGroupLayout(B_VERTICAL); - dynamicLayout->SetInsets(B_USE_DEFAULT_SPACING, - dynamicBox->TopBorderOffset() * 2 + 10, - B_USE_DEFAULT_SPACING, B_USE_DEFAULT_SPACING); - dynamicLayout->SetSpacing(B_USE_DEFAULT_SPACING); - dynamicBox->SetLayout(dynamicLayout); - mainLayout->AddView(dynamicBox); - - fColorStepView = new ColorStepView(frame); - fColorStepView->SetFrequencys(fDriverInterface.GetCpuFrequencyStates()); - - fIntegrationTime = new BTextControl(BRect(0, 0, Bounds().Width(), 10), - "intergal", B_TRANSLATE("Integration time [ms]: "), "", - new BMessage(kIntegrationTimeChanged)); - fIntegrationTime->SetDivider(Bounds().Width() * 3 / 4); - fIntegrationTime->SetAlignment(B_ALIGN_RIGHT, B_ALIGN_LEFT); - - dynamicLayout->AddView(fColorStepView); - dynamicLayout->AddView(fIntegrationTime); - - // status view - BBox *statusBox = new BBox(rect, "statusBox"); - statusBox->SetLabel(B_TRANSLATE("CPU frequency status view")); - BGroupLayout* statusLayout = new BGroupLayout(B_HORIZONTAL); - statusLayout->SetInsets(10, statusBox->TopBorderOffset() * 2 + 10, 10, 10); - statusLayout->SetSpacing(10); - statusBox->SetLayout(statusLayout); - mainLayout->AddView(statusBox); - - fStatusView = new StatusView(BRect(0, 0, 5, 5), false, fStorage); - fStatusView->ShowPopUpMenu(false); - - fInstallButton = new BButton("installButton", - B_TRANSLATE("Install replicant into Deskbar"), - new BMessage(kInstallIntoDeskbar)); - - statusLayout->AddView(fStatusView); - statusLayout->AddItem(BSpaceLayoutItem::CreateGlue()); - statusLayout->AddView(fInstallButton); -} - - -void -CPUFrequencyView::MessageReceived(BMessage* message) -{ - freq_preferences* pref = fStorage->GetPreferences(); - bool configChanged = false; - - switch (message->what) { - case kUpdatedPreferences: - fStatusView->MessageReceived(message); - if (pref->mode == DYNAMIC) { - fColorStepView->SetEnabled(true); - fIntegrationTime->SetEnabled(true); - } - else { - fColorStepView->SetEnabled(false); - fIntegrationTime->SetEnabled(false); - } - configChanged = true; - break; - - case kSteppingChanged: - // from ColorStepView - pref->stepping_threshold = fColorStepView->GetSliderPosition(); - fStorage->SavePreferences(); - configChanged = true; - break; - - case kIntegrationTimeChanged: - _ReadIntegrationTime(); - fStorage->SavePreferences(); - configChanged = true; - break; - - case kInstallIntoDeskbar: - _InstallReplicantInDeskbar(); - break; - - case kRevertMsg: - case kDefaultMsg: - fStatusView->UpdateCPUFreqState(); - _UpdateViews(); - break; - default: - BView::MessageReceived(message); - } - - if (configChanged) - Window()->PostMessage(kConfigChangedMsg); -} - - -void -CPUFrequencyView::AttachedToWindow() -{ - fFrequencyMenu = new FrequencyMenu(fPolicyMenu, this, fStorage, - &fDriverInterface); - AddFilter(fFrequencyMenu); - - fColorStepView->SetTarget(this); - fIntegrationTime->SetTarget(this); - fInstallButton->SetTarget(this); - - _UpdateViews(); -} - - -void -CPUFrequencyView::DetachedFromWindow() -{ - // emty menu for the case the view is attached again - while (true) { - BMenuItem* item = fPolicyMenu->RemoveItem(int32(0)); - if (!item) - break; - delete item; - } - if (RemoveFilter(fFrequencyMenu)) - delete fFrequencyMenu; - - _ReadIntegrationTime(); -} - - -status_t -our_image(image_info& image) -{ - int32 cookie = 0; - while (get_next_image_info(B_CURRENT_TEAM, &cookie, &image) == B_OK) { - if ((char *)our_image >= (char *)image.text - && (char *)our_image <= (char *)image.text + image.text_size) - return B_OK; - } - - return B_ERROR; -}; - - -void -CPUFrequencyView::_InstallReplicantInDeskbar() -{ - image_info info; - entry_ref ref; - if (our_image(info) == B_OK - && get_ref_for_path(info.name, &ref) == B_OK) { - BDeskbar deskbar; - deskbar.AddItem(&ref); - } -} - - -void -CPUFrequencyView::_UpdateViews() -{ - fFrequencyMenu->UpdateMenu(); - freq_preferences* pref = fStorage->GetPreferences(); - fColorStepView->SetSliderPosition(pref->stepping_threshold); - if (pref->mode == DYNAMIC) { - fColorStepView->SetEnabled(true); - fIntegrationTime->SetEnabled(true); - } - else { - fColorStepView->SetEnabled(false); - fIntegrationTime->SetEnabled(false); - } - - BString out; - out << pref->integration_time / kMilliSecond; - fIntegrationTime->SetText(out.String()); -} - - -void -CPUFrequencyView::_ReadIntegrationTime() -{ - freq_preferences* pref = fStorage->GetPreferences(); - bigtime_t integration_time = atoi(fIntegrationTime->Text()) * kMilliSecond; - if (integration_time == 0) { - BString out; - out << pref->integration_time / kMilliSecond; - fIntegrationTime->SetText(out.String()); - } - else { - pref->integration_time = integration_time; - } -} diff --git a/src/preferences/cpufrequency/CPUFrequencyView.h b/src/preferences/cpufrequency/CPUFrequencyView.h deleted file mode 100644 index 1d9a164ab9..0000000000 --- a/src/preferences/cpufrequency/CPUFrequencyView.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright 2009, Haiku, Inc. All Rights Reserved. - * Distributed under the terms of the MIT License. - * - * Authors: - * Clemens Zeidler, haiku@clemens-zeidler.de - */ - -#ifndef CPUFREQUENCYVIEW_h -#define CPUFREQUENCYVIEW_h - -#include "DriverInterface.h" -#include "ColorStepView.h" -#include "PreferencesWindow.h" - -#include -#include -#include -#include - - -extern const char* kPrefSignature; -extern const char* kPreferencesFileName; - -enum stepping_mode { - DYNAMIC, - PERFORMANCE, - LOW_ENERGIE, - CUSTOM -}; - - -struct freq_preferences -{ - bool IsEqual(const freq_preferences& prefs) { - if (mode == prefs.mode && custom_stepping == prefs.custom_stepping - && stepping_threshold == prefs.stepping_threshold - && integration_time == prefs.integration_time) - return true; - return false; - } - - // stepping mode - stepping_mode mode; - int16 custom_stepping; - - // dynamic stepping - float stepping_threshold; - bigtime_t integration_time; -}; - - -const freq_preferences kDefaultPreferences = -{ - DYNAMIC, - -1, - 0.25, - 500000 //half second -}; - - -class FrequencyMenu; -class StatusView; - -class CPUFrequencyView : public BView -{ - public: - CPUFrequencyView(BRect frame, - PreferencesStorage* storage); - virtual void MessageReceived(BMessage* message); - - virtual void AttachedToWindow(); - virtual void DetachedFromWindow(); - - private: - void _InstallReplicantInDeskbar(); - void _UpdateViews(); - void _ReadIntegrationTime(); - - BMenu* fPolicyMenu; - FrequencyMenu* fFrequencyMenu; - ColorStepView* fColorStepView; - BTextControl* fIntegrationTime; - StatusView* fStatusView; - BButton* fInstallButton; - - PreferencesStorage* fStorage; - CPUFreqDriverInterface fDriverInterface; -}; - -#endif diff --git a/src/preferences/cpufrequency/ColorStepView.cpp b/src/preferences/cpufrequency/ColorStepView.cpp deleted file mode 100644 index 7b5a9caefd..0000000000 --- a/src/preferences/cpufrequency/ColorStepView.cpp +++ /dev/null @@ -1,333 +0,0 @@ -/* - * Copyright 2009, Haiku, Inc. All Rights Reserved. - * Distributed under the terms of the MIT License. - * - * Authors: - * Clemens Zeidler, haiku@clemens-zeidler.de - */ - -#include "ColorStepView.h" - -#include - -#include -#include -#include - - -#undef B_TRANSLATION_CONTEXT -#define B_TRANSLATION_CONTEXT "Color Step View" - - -const int32 kColorBarHeight = 15; - -const uint32 kMSGSliderChanged = '&slc'; - - -ColorStepView::ColorStepView(BRect frame) - : BControl(frame, "ColorStepView", "", new BMessage(kSteppingChanged), - B_FOLLOW_ALL, B_WILL_DRAW), - fOffScreenView(NULL), - fOffScreenBitmap(NULL) -{ - fPerformanceList = new PerformanceList(20, true); - - fSliderPosition = 0; - fNSteps = 0; - fLowFreqColor.red = 0; - fLowFreqColor.blue = 255; - fLowFreqColor.green = 0; - - fHighFreqColor.red = 255; - fHighFreqColor.blue = 0; - fHighFreqColor.green = 0; - - fMinFrequencyLabel = "? MHz"; - fMaxFrequencyLabel = "? MHz"; - _InitView(); -} - - -ColorStepView::~ColorStepView() -{ - delete fPerformanceList; -} - - -void -ColorStepView::AttachedToWindow() -{ - fSlider->SetTarget(this); - - if (!fOffScreenView) { - fOffScreenView = new BView(Bounds(), "", B_FOLLOW_ALL, B_WILL_DRAW); - } - if (!fOffScreenBitmap) { - fOffScreenBitmap = new BBitmap(Bounds(), B_CMAP8, true, false); - Window()->Lock(); - if (fOffScreenBitmap && fOffScreenView) - fOffScreenBitmap->AddChild(fOffScreenView); - Window()->Unlock(); - } -} - - -void -ColorStepView::DetachedFromWindow() -{ - BView::DetachedFromWindow(); - - if (fOffScreenBitmap) { - delete fOffScreenBitmap; - fOffScreenBitmap = NULL; - fOffScreenView = NULL; - } -} - - -void -ColorStepView::FrameResized(float w,float h) -{ - BView::FrameResized(w, h); - - BRect bounds(Bounds()); - - if (bounds.right <= 0.0f || bounds.bottom <= 0.0f) - return; - - if (fOffScreenBitmap) { - fOffScreenBitmap->RemoveChild(fOffScreenView); - delete fOffScreenBitmap; - - fOffScreenView->ResizeTo(bounds.Width(), bounds.Height()); - - fOffScreenBitmap = new BBitmap(Bounds(), B_RGBA32, true, false); - fOffScreenBitmap->AddChild(fOffScreenView); - } - - Invalidate(); -} - - -void -ColorStepView::GetPreferredSize(float *width, float *height) -{ - *width = Frame().Width(); - font_height fontHeight; - GetFontHeight(&fontHeight); - - *height = fSlider->Frame().Height(); - *height += kColorBarHeight; - *height += fontHeight.descent + fontHeight.ascent + 5; -} - - -void -ColorStepView::Draw(BRect updateRect) -{ - BView *view = NULL; - if(fOffScreenView){ - view = fOffScreenView; - } - else{ - view = this; - } - - if (!fOffScreenBitmap || !fOffScreenBitmap->Lock()) - return; - view->SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR)); - - view->SetHighColor(ui_color(B_PANEL_BACKGROUND_COLOR)); - view->FillRect(updateRect); - - BRect colorBarRect = fSlider->BarFrame(); - colorBarRect.top = 0; - colorBarRect.bottom = kColorBarHeight; - colorBarRect.OffsetTo(colorBarRect.left, fSlider->Frame().bottom); - - float pos = 0.0; - for (int i = fPerformanceList->CountItems() - 1; i >= 0 ; i--) { - performance_step* perfState = fPerformanceList->ItemAt(i); - - float nextPos = perfState->cpu_usage; - float width = colorBarRect.Width(); - - BRect subRect(colorBarRect); - subRect.left += pos * width; - subRect.right = colorBarRect.left + nextPos * width; - - view->SetHighColor(perfState->color); - view->FillRect(subRect); - - pos = nextPos; - } - // draw label - if (IsEnabled()) - view->SetHighColor(0, 0, 0); - else - view->SetHighColor(tint_color(LowColor(), B_DISABLED_LABEL_TINT)); - - font_height fontHeight; - GetFontHeight(&fontHeight); - float totalFontHeight = fontHeight.descent + fontHeight.ascent; - - view->DrawString(fMinFrequencyLabel.String(), - BPoint(0.0, - colorBarRect.bottom + totalFontHeight + 5)); - - view->DrawString(fMaxFrequencyLabel.String(), - BPoint(Bounds().right - - StringWidth(fMaxFrequencyLabel.String()), - colorBarRect.bottom + totalFontHeight + 5)); - - // blit bitmap - view->Sync(); - fOffScreenBitmap->Unlock(); - DrawBitmap(fOffScreenBitmap, B_ORIGIN); - - BView::Draw(updateRect); -} - - -void -ColorStepView::MessageReceived(BMessage *message) -{ - switch (message->what) { - case kMSGSliderChanged: - fSliderPosition = fSlider->Position(); - _CalculatePerformanceSteps(); - Invalidate(); - break; - case kSteppingChanged: - Invoke(); - break; - default: - BView::MessageReceived(message); - break; - } -} - - -void -ColorStepView::SetEnabled(bool enabled) -{ - fSlider->SetEnabled(enabled); - BControl::SetEnabled(enabled); -} - - -void -ColorStepView::SetFrequencys(StateList *list) -{ - fStateList = list; - fNSteps = fStateList->CountItems(); - if (fNSteps >= 2) { - float minFreq = fStateList->ItemAt(fNSteps - 1)->frequency; - float maxFreq = fStateList->ItemAt(0)->frequency; - fMinFrequencyLabel = CreateFrequencyString(minFreq); - fMaxFrequencyLabel = CreateFrequencyString(maxFreq); - } - - // fit size of fPerformanceList - int32 perfNumber = fPerformanceList->CountItems(); - if (perfNumber < fNSteps) { - for (int i = 0; i < fNSteps - perfNumber; i++) - fPerformanceList->AddItem(new performance_step); - } else { - for (int i = 0; i < perfNumber - fNSteps; i++) - fPerformanceList->RemoveItemAt(0); - } - // and fill the list - _CalculatePerformanceSteps(); - -} - - -PerformanceList* -ColorStepView::GetPerformanceSteps() -{ - return fPerformanceList; -} - - -BString -ColorStepView::CreateFrequencyString(uint16 frequency) -{ - BString string = ""; - if (frequency >= 1000) { - char buffer [10]; - sprintf (buffer, "%.1f", float(frequency) / 1000); - string << buffer; - string += " GHz"; - } - else { - string << frequency; - string += " MHz"; - } - return string; -} - - - -float -ColorStepView::UsageOfStep(int32 step, int32 nSteps, float base) -{ - float singleWidth = (1 - base) / (nSteps - 1); - return base + singleWidth * step; -} - - -void -ColorStepView::_InitView() -{ - SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); - - BRect sliderFrame(Bounds()); - - fSlider = new BSlider(sliderFrame, "StepSlider", - B_TRANSLATE("Step up by CPU usage"), - new BMessage(kSteppingChanged), 0, 100); - fSlider->SetModificationMessage(new BMessage(kMSGSliderChanged)); - - fSliderPosition = 0.25 - fNSteps * 0.05; - fSlider->SetPosition(fSliderPosition); - fSlider->SetLimitLabels("0%", "100%"); - fSlider->SetHashMarks(B_HASH_MARKS_BOTTOM); - fSlider->SetHashMarkCount(5); - AddChild(fSlider); -} - - -void -ColorStepView::_CalculatePerformanceSteps() -{ - for (int i = 0; i < fNSteps; i++) { - // begin with the lowest frequency - performance_step* perfState = fPerformanceList->ItemAt(fNSteps -1 - i); - perfState->cpu_usage = _PositonStep(i); - _ColorStep(i, perfState->color); - } -} - - -float -ColorStepView::_PositonStep(int32 step) -{ - if (step >= fNSteps) - return 1.0; - - return UsageOfStep(step, fNSteps, fSliderPosition); -} - - -void -ColorStepView::_ColorStep(int32 step, rgb_color &color) -{ - color.red = fLowFreqColor.red - + (fHighFreqColor.red - fLowFreqColor.red) * step / (fNSteps - 1); - color.green = fLowFreqColor.green - + (fHighFreqColor.green - fLowFreqColor.green) * step / (fNSteps - 1); - color.blue = fLowFreqColor.blue - + (fHighFreqColor.blue - fLowFreqColor.blue) * step / (fNSteps - 1); -} - diff --git a/src/preferences/cpufrequency/ColorStepView.h b/src/preferences/cpufrequency/ColorStepView.h deleted file mode 100644 index 0c44ac5b9b..0000000000 --- a/src/preferences/cpufrequency/ColorStepView.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2009, Haiku, Inc. All Rights Reserved. - * Distributed under the terms of the MIT License. - * - * Authors: - * Clemens Zeidler, haiku@clemens-zeidler.de - */ - -#ifndef COLORSTEPVIEW_H -#define COLORSTEPVIEW_H - -#include -#include -#include -#include -#include - -#include "DriverInterface.h" - -const uint32 kSteppingChanged = '&spc'; - -struct performance_step { - float cpu_usage; // upper limit - rgb_color color; -}; - - -typedef BObjectList PerformanceList; - - -class ColorStepView : public BControl -{ - public: - ColorStepView(BRect frame); - ~ColorStepView(); - virtual void AttachedToWindow(); - virtual void DetachedFromWindow(); - virtual void FrameResized(float w,float h); - - virtual void GetPreferredSize(float *width, float *height); - virtual void Draw(BRect updateRect); - virtual void MessageReceived(BMessage *message); - virtual void SetEnabled(bool enabled); - - void SetFrequencys(StateList *list); - PerformanceList* GetPerformanceSteps(); - static BString CreateFrequencyString(uint16 frequency); - - void SetSliderPosition(float pos) { - fSlider->SetPosition(pos); - fSliderPosition = pos; - _CalculatePerformanceSteps(); - } - float GetSliderPosition() { return fSliderPosition; } - - static float UsageOfStep(int32 step, int32 nSteps, float base); - - private: - void _InitView(); - void _CalculatePerformanceSteps(); - float _PositonStep(int32 step); - void _ColorStep(int32 step, rgb_color &color); - - BSlider* fSlider; - - float fSliderPosition; - int32 fNSteps; - rgb_color fLowFreqColor; - rgb_color fHighFreqColor; - - BView* fOffScreenView; - BBitmap* fOffScreenBitmap; - - BString fMinFrequencyLabel; - BString fMaxFrequencyLabel; - - PerformanceList* fPerformanceList; - StateList* fStateList; -}; - - -#endif diff --git a/src/preferences/cpufrequency/DriverInterface.cpp b/src/preferences/cpufrequency/DriverInterface.cpp deleted file mode 100644 index 099f7bc990..0000000000 --- a/src/preferences/cpufrequency/DriverInterface.cpp +++ /dev/null @@ -1,222 +0,0 @@ -/* - * Copyright 2009, Haiku, Inc. All Rights Reserved. - * Distributed under the terms of the MIT License. - * - * Authors: - * Clemens Zeidler, haiku@clemens-zeidler.de - */ - -#include "DriverInterface.h" - -#include - -#include -#include -#include -#include - - -#define DRIVER_DIR "/dev/power" - -CPUFreqDriverInterface::CPUFreqDriverInterface() - : fInitOK(false), - fDriverHandler(-1), - fIsWatching(false), - fWatchingMessenger(NULL) -{ - fFrequencyStates = new StateList(20, true); - - if (_FindSpeedStepDriver(DRIVER_DIR) == B_OK) - fInitOK = true; - - status_t ret; - freq_info states[MAX_CPU_FREQUENCY_STATES]; - ret = ioctl(fDriverHandler, GET_CPU_FREQ_STATES, &states, - sizeof(freq_info) * MAX_CPU_FREQUENCY_STATES); - if (ret != B_OK) - return; - - for (int i = 0; i < MAX_CPU_FREQUENCY_STATES && states[i].frequency != 0; - i++) { - fFrequencyStates->AddItem(new freq_info(states[i])); - } -} - - -CPUFreqDriverInterface::~CPUFreqDriverInterface() -{ - StopWatching(); - delete fFrequencyStates; - - if (InitCheck() == B_OK) - close(fDriverHandler); -} - - -status_t -CPUFreqDriverInterface::InitCheck() -{ - if (fInitOK) - return B_OK; - return B_ERROR; -} - - -StateList* -CPUFreqDriverInterface::GetCpuFrequencyStates() -{ - return fFrequencyStates; -} - - -freq_info* -CPUFreqDriverInterface::GetCurrentFrequencyState() -{ - uint16 stateId = 0; - status_t ret; - ret = ioctl(fDriverHandler, GET_CURENT_CPU_FREQ_STATE, &stateId, - sizeof(uint16)); - if (ret != B_OK) - return NULL; - int32 i = 0; - while (true) { - freq_info* state = fFrequencyStates->ItemAt(i); - if (!state) - break; - i++; - - if (state->id == stateId) - return state; - } - return NULL; -} - - -int32 -CPUFreqDriverInterface::GetNumberOfFrequencyStates() -{ - return fFrequencyStates->CountItems(); -} - - -status_t -CPUFreqDriverInterface::SetFrequencyState(const freq_info* state) -{ - status_t ret; - ret = ioctl(fDriverHandler, SET_CPU_FREQ_STATE, &(state->id), - sizeof(uint16)); - return ret; -} - - -status_t -CPUFreqDriverInterface::StartWatching(BHandler* target) -{ - if (fIsWatching) - return B_ERROR; - - if (fWatchingMessenger) - delete fWatchingMessenger; - fWatchingMessenger = new BMessenger(target); - - status_t status = B_ERROR; - fThreadId = spawn_thread(&_ThreadWatchFreqFunction, "FreqThread", - B_LOW_PRIORITY, this); - if (fThreadId >= 0) - status = resume_thread(fThreadId); - else - return fThreadId; - - if (status == B_OK) { - fIsWatching = true; - return B_OK; - } - return status; -} - - -status_t -CPUFreqDriverInterface::StopWatching() -{ - - if (fIsWatching && - ioctl(fDriverHandler, STOP_WATCHING_CPU_FREQ) == B_OK) - { - status_t status; - status = wait_for_thread(fThreadId, &status); - - delete fWatchingMessenger; - fWatchingMessenger = NULL; - - fIsWatching = false; - } - - return B_ERROR; -} - - -int32 -CPUFreqDriverInterface::_ThreadWatchFreqFunction(void* data) -{ - CPUFreqDriverInterface* that = (CPUFreqDriverInterface*)data; - that->_WatchFrequency(); - return 0; -} - - -void -CPUFreqDriverInterface::_WatchFrequency() -{ - uint16 newId = 0; - while (ioctl(fDriverHandler, WATCH_CPU_FREQ, &newId, - sizeof(uint16)) == B_OK) - { - int i = 0; - while (true) { - freq_info* state = fFrequencyStates->ItemAt(i); - if (!state) - break; - i++; - - if (state->id == newId) { - BMessage msg(kMSGFrequencyChanged); - msg.AddPointer("freq_info", state); - fWatchingMessenger->SendMessage(&msg); - break; - } - } - } -} - - -status_t -CPUFreqDriverInterface::_FindSpeedStepDriver(const char* path) -{ - BDirectory dir(path); - BEntry entry; - - while (dir.GetNextEntry(&entry) == B_OK) { - BPath path; - entry.GetPath(&path); - - if (entry.IsDirectory()) { - if (_FindSpeedStepDriver(path.Path()) == B_OK) - return B_OK; - } - else { - fDriverHandler = open(path.Path(), O_RDWR); - if (fDriverHandler >= 0) { - uint32 magicId = 0; - status_t ret; - ret = ioctl(fDriverHandler, IDENTIFY_DEVICE, &magicId, - sizeof(uint32)); - if (ret == B_OK && magicId == kMagicFreqID) - return B_OK; - else - close(fDriverHandler); - } - } - - } - return B_ERROR; -} diff --git a/src/preferences/cpufrequency/DriverInterface.h b/src/preferences/cpufrequency/DriverInterface.h deleted file mode 100644 index 7a31f04de9..0000000000 --- a/src/preferences/cpufrequency/DriverInterface.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2009, Haiku, Inc. All Rights Reserved. - * Distributed under the terms of the MIT License. - * - * Authors: - * Clemens Zeidler, haiku@clemens-zeidler.de - */ - -#ifndef DRIVERINTERFACE_H -#define DRIVERINTERFACE_H - -#include -#include - -#include "device/power_managment.h" - -const uint32 kMSGFrequencyChanged = '&frc'; - -typedef BObjectList StateList; - - -class CPUFreqDriverInterface -{ - public: - CPUFreqDriverInterface(); - ~CPUFreqDriverInterface(); - - status_t InitCheck(); - StateList* GetCpuFrequencyStates(); - freq_info* GetCurrentFrequencyState(); - int32 GetNumberOfFrequencyStates(); - status_t SetFrequencyState(const freq_info* state); - - status_t StartWatching(BHandler* target); - status_t StopWatching(); - private: - static int32 _ThreadWatchFreqFunction(void* data); - void _WatchFrequency(); - - thread_id fThreadId; - status_t _FindSpeedStepDriver(const char* path); - - bool fInitOK; - int32 fDriverHandler; - - StateList* fFrequencyStates; - - bool fIsWatching; - BMessenger* fWatchingMessenger; -}; - - -#endif diff --git a/src/preferences/cpufrequency/Jamfile b/src/preferences/cpufrequency/Jamfile deleted file mode 100644 index a752a37d63..0000000000 --- a/src/preferences/cpufrequency/Jamfile +++ /dev/null @@ -1,24 +0,0 @@ -SubDir HAIKU_TOP src preferences cpufrequency ; - -UsePrivateHeaders shared ; - -Preference CPUFrequency : - ColorStepView.cpp - CPUFrequencyView.cpp - DriverInterface.cpp - main.cpp - StatusView.cpp - : be $(TARGET_LIBSUPC++) localestub - : cpufrequency.rdef - ; - -DoCatalogs CPUFrequency : - x-vnd.Haiku-CPUFrequencyPref - : - ColorStepView.cpp - CPUFrequencyView.cpp - main.cpp - StatusView.cpp - PreferencesWindow.h -; - diff --git a/src/preferences/cpufrequency/PreferencesWindow.h b/src/preferences/cpufrequency/PreferencesWindow.h deleted file mode 100644 index 03e99002a8..0000000000 --- a/src/preferences/cpufrequency/PreferencesWindow.h +++ /dev/null @@ -1,481 +0,0 @@ -/* - * Copyright 2009, Haiku, Inc. All Rights Reserved. - * Distributed under the terms of the MIT License. - * - * Authors: - * Clemens Zeidler, haiku@clemens-zeidler.de - */ -#ifndef PREFERENCES_WINDOW_h -#define PREFERENCES_WINDOW_h - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#if DEBUG -# define LOG(text...) PRINT((text)) -#else -# define LOG(text...) -#endif - - -#undef B_TRANSLATION_CONTEXT -#define B_TRANSLATION_CONTEXT "Pref Window" - -// messages PrefFileWatcher -const uint32 kUpdatedPreferences = '&UdP'; - - -template -class PreferencesStorage { -public: - PreferencesStorage(const char* file, - const Preferences& defaultPreferences); - ~PreferencesStorage(); - - void Revert(); - void Defaults(); - - BPoint WindowPosition() {return fWindowPosition; } - void SetWindowPosition(BPoint position) - { fWindowPosition = position; } - - Preferences* GetPreferences() { return &fPreferences; } - - status_t LoadPreferences(); - status_t SavePreferences(); - - BString& PreferencesFile() { return fPreferencesFile; } - status_t GetPreferencesPath(BPath &path); - - bool DefaultsSet(); - bool StartPrefsSet(); - -private: - BString fPreferencesFile; - - Preferences fPreferences; - Preferences fStartPreferences; - const Preferences& fDefaultPreferences; - BPoint fWindowPosition; -}; - - -template -class PrefFileWatcher : public BMessageFilter { -public: - PrefFileWatcher( - PreferencesStorage* storage, - BHandler* target); - virtual ~PrefFileWatcher(); - - virtual filter_result Filter(BMessage* message, BHandler** _target); - -private: - PreferencesStorage* fPreferencesStorage; - node_ref fPreferencesNode; - node_ref fPreferencesDirectoryNode; - - BHandler* fTarget; -}; - - -template -class PreferencesWindow : public BWindow, - public PreferencesStorage { -public: - PreferencesWindow(const char* title, - const char* file, - const Preferences& defaultPreferences); - virtual ~PreferencesWindow(); - virtual void MessageReceived(BMessage *msg); - virtual bool QuitRequested(); - - virtual bool SetPreferencesView(BView* prefView); - -private: - void _MoveToPosition(); - void _UpdateButtons(); - - BView* fPreferencesView; - BButton* fRevertButton; - BButton* fDefaultButton; - BGroupLayout* fRootLayout; -}; - - -const uint32 kDefaultMsg = 'dems'; -const uint32 kRevertMsg = 'rems'; -const uint32 kConfigChangedMsg = '&cgh'; - - -template -PreferencesStorage::PreferencesStorage(const char* file, - const Preferences& defaultPreferences) - : - fDefaultPreferences(defaultPreferences) -{ - // default center position - fWindowPosition.x = -1; - fWindowPosition.y = -1; - - fPreferencesFile = file; - if (LoadPreferences() != B_OK) - Defaults(); - fStartPreferences = fPreferences; -} - - -template -PreferencesStorage::~PreferencesStorage() -{ - SavePreferences(); -} - - -template -void -PreferencesStorage::Revert() -{ - fPreferences = fStartPreferences; -} - - -template -void -PreferencesStorage::Defaults() -{ - fPreferences = fDefaultPreferences; -} - - -template -status_t -PreferencesStorage::GetPreferencesPath(BPath &path) -{ - status_t status = find_directory(B_USER_SETTINGS_DIRECTORY, &path); - if (status < B_OK) - return status; - - return path.Append(fPreferencesFile.String()); -} - - -template -status_t -PreferencesStorage::LoadPreferences() -{ - BPath path; - status_t status = GetPreferencesPath(path); - if (status != B_OK) - return status; - - BFile settingsFile(path.Path(), B_READ_ONLY); - status = settingsFile.InitCheck(); - if (status != B_OK) - return status; - - if (settingsFile.Read(&fWindowPosition, sizeof(BPoint)) - != sizeof(BPoint)) { - LOG("failed to load settings\n"); - return B_ERROR; - } - - if (settingsFile.Read(&fPreferences, sizeof(Preferences)) - != sizeof(Preferences)) { - LOG("failed to load settings\n"); - return B_ERROR; - } - - return B_OK; -} - - -template -status_t -PreferencesStorage::SavePreferences() -{ - BPath path; - status_t status = GetPreferencesPath(path); - if (status != B_OK) - return status; - - BFile settingsFile(path.Path(), B_READ_WRITE | B_CREATE_FILE); - status = settingsFile.InitCheck(); - if (status != B_OK) { - LOG("InitCheck() settings file failed \n"); - return status; - } - - if (settingsFile.Write(&fWindowPosition, sizeof(BPoint)) - != sizeof(BPoint)) { - LOG("can't save window position\n"); - return B_ERROR; - } - - if (settingsFile.Write(&fPreferences, sizeof(Preferences)) - != sizeof(Preferences)) { - LOG("can't save settings\n"); - return B_ERROR; - } - - return B_OK; -} - - -template -bool -PreferencesStorage::DefaultsSet() -{ - return fPreferences.IsEqual(fDefaultPreferences); -} - - -template -bool -PreferencesStorage::StartPrefsSet() -{ - return fPreferences.IsEqual(fStartPreferences); -} - - -template -PrefFileWatcher::PrefFileWatcher( - PreferencesStorage* storage, BHandler* target) - : - BMessageFilter(B_PROGRAMMED_DELIVERY, B_ANY_SOURCE), - fPreferencesStorage(storage), - fTarget(target) -{ - BPath path; - find_directory(B_USER_SETTINGS_DIRECTORY, &path); - - BEntry entry(path.Path()); - if (entry.GetNodeRef(&fPreferencesDirectoryNode) == B_OK) - watch_node(&fPreferencesDirectoryNode, B_WATCH_DIRECTORY, fTarget); - - path.Append(fPreferencesStorage->PreferencesFile().String()); - entry.SetTo(path.Path()); - - if (entry.GetNodeRef(&fPreferencesNode) == B_OK) - watch_node(&fPreferencesNode, B_WATCH_STAT, fTarget); -} - - -template -PrefFileWatcher::~PrefFileWatcher() -{ - stop_watching(fTarget); -} - - -template -filter_result -PrefFileWatcher::Filter(BMessage *msg, BHandler **target) -{ - const char *name; - ino_t dir = -1; - filter_result result = B_DISPATCH_MESSAGE; - int32 opcode; - BPath path; - node_ref nref; - - if (msg->what != B_NODE_MONITOR - || msg->FindInt32("opcode", &opcode) != B_OK) - return result; - - switch (opcode) { - case B_ENTRY_MOVED: - msg->FindInt64("to directory", dir); - if (dir != fPreferencesDirectoryNode.node) - break; - // supposed to fall through - - case B_ENTRY_CREATED: - msg->FindString("name", &name); - fPreferencesStorage->GetPreferencesPath(path); - if (path.Path() == name) { - msg->FindInt32("device", &fPreferencesNode.device); - msg->FindInt64("node", &fPreferencesNode.node); - watch_node(&fPreferencesNode, B_WATCH_STAT, fTarget); - } - fPreferencesStorage->LoadPreferences(); - msg->what = kUpdatedPreferences; - break; - - case B_ENTRY_REMOVED: - msg->FindInt32("device", &nref.device); - msg->FindInt64("node", &nref.node); - if (fPreferencesNode == nref) { - // stop all watching - stop_watching(fTarget); - // and start watching the directory again - watch_node(&fPreferencesDirectoryNode, B_WATCH_DIRECTORY, - fTarget); - msg->what = kUpdatedPreferences; - } - break; - - case B_STAT_CHANGED: - msg->FindInt32("device", &nref.device); - msg->FindInt64("node", &nref.node); - if (fPreferencesNode == nref) { - fPreferencesStorage->LoadPreferences(); - msg->what = kUpdatedPreferences; - } - break; - } - return result; -} - - -template -PreferencesWindow::PreferencesWindow(const char* title, - const char* file, const Preferences& defaultPreferences) - : - BWindow(BRect(50, 50, 400, 350), title, B_TITLED_WINDOW, - B_NOT_RESIZABLE | B_NOT_ZOOMABLE | B_ASYNCHRONOUS_CONTROLS), - PreferencesStorage(file, defaultPreferences), - fPreferencesView(NULL) -{ - BGroupView* buttonView = new BGroupView(B_HORIZONTAL); - fDefaultButton = new BButton(B_TRANSLATE("Defaults"), - new BMessage(kDefaultMsg)); - buttonView->AddChild(fDefaultButton); - - fRevertButton = new BButton(B_TRANSLATE("Revert"), - new BMessage(kRevertMsg)); - buttonView->AddChild(fRevertButton); - buttonView->GetLayout()->AddItem(BSpaceLayoutItem::CreateGlue()); - - _UpdateButtons(); - - SetLayout(new BGroupLayout(B_VERTICAL)); - fRootLayout = new BGroupLayout(B_VERTICAL); - fRootLayout->SetInsets(B_USE_DEFAULT_SPACING); - fRootLayout->SetSpacing(B_USE_DEFAULT_SPACING); - BView* rootView = new BView("root view", 0, fRootLayout); - AddChild(rootView); - rootView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); - - fRootLayout->AddView(buttonView); - - BSize size = fRootLayout->PreferredSize(); - ResizeTo(size.width, size.height); - _MoveToPosition(); -} - - -template -PreferencesWindow::~PreferencesWindow() -{ - PreferencesStorage::SetWindowPosition(Frame().LeftTop()); -} - - -template -void -PreferencesWindow::MessageReceived(BMessage *msg) -{ - switch(msg->what) - { - case kConfigChangedMsg: - _UpdateButtons(); - break; - - case kDefaultMsg: - PreferencesStorage::Defaults(); - _UpdateButtons(); - if (fPreferencesView) - PostMessage(kDefaultMsg, fPreferencesView); - break; - - case kRevertMsg: - PreferencesStorage::Revert(); - _UpdateButtons(); - if (fPreferencesView) - PostMessage(kRevertMsg, fPreferencesView); - break; - - default: - BWindow::MessageReceived(msg); - } -} - - -template -bool -PreferencesWindow::QuitRequested() -{ - be_app->PostMessage(B_QUIT_REQUESTED); - return true; -} - - -template -bool -PreferencesWindow::SetPreferencesView(BView* prefView) -{ - if (fPreferencesView) - return false; - - fPreferencesView = prefView; - fRootLayout->AddView(0, fPreferencesView); - - BSize size = fRootLayout->PreferredSize(); - ResizeTo(size.width, size.height); - _MoveToPosition(); - - return true; -} - - -template -void -PreferencesWindow::_MoveToPosition() -{ - BPoint position = PreferencesStorage::WindowPosition(); - // center window on screen if it had a bad position - if (position.x < 0 && position.y < 0){ - BRect rect = BScreen().Frame(); - BRect windowFrame = Frame(); - position.x = (rect.Width() - windowFrame.Width()) / 2; - position.y = (rect.Height() - windowFrame.Height()) / 2; - } - MoveTo(position); -} - - -template -void -PreferencesWindow::_UpdateButtons() -{ - if (!PreferencesStorage::DefaultsSet()) - fDefaultButton->SetEnabled(true); - else - fDefaultButton->SetEnabled(false); - if (!PreferencesStorage::StartPrefsSet()) - fRevertButton->SetEnabled(true); - else - fRevertButton->SetEnabled(false); -} - - -#undef B_TRANSLATION_CONTEXT - -#endif // PREFERENCES_WINDOW_h diff --git a/src/preferences/cpufrequency/StatusView.cpp b/src/preferences/cpufrequency/StatusView.cpp deleted file mode 100644 index 40843a4e31..0000000000 --- a/src/preferences/cpufrequency/StatusView.cpp +++ /dev/null @@ -1,712 +0,0 @@ -/* - * Copyright 2009, Haiku, Inc. All Rights Reserved. - * Distributed under the terms of the MIT License. - * - * Authors: - * Clemens Zeidler, haiku@clemens-zeidler.de - */ - - -#include "StatusView.h" - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "CPUFrequencyView.h" - - -extern "C" _EXPORT BView *instantiate_deskbar_item(void); - - -#undef B_TRANSLATION_CONTEXT -#define B_TRANSLATION_CONTEXT "Status view" -#define MAX_FREQ_STRING "9999MHz" - - -/* This file is used both by the preference panel and the deskbar replicant. - * This make it needs two different BCatalogs depending on the context. - * As this is not really possible with the current way BCatalog are built, - * we get the catalog by hand. This makes us unable to use the TR macros, - * and then collectcatkeys will not see the strings in the file. - * So we mark them explicitly here. - */ -B_TRANSLATE_MARK_VOID("Dynamic performance"); -B_TRANSLATE_MARK_VOID("High performance"); -B_TRANSLATE_MARK_VOID("Low energy"); -B_TRANSLATE_MARK_VOID("Set state"); -B_TRANSLATE_MARK_VOID("CPUFrequency\n" - "\twritten by Clemens Zeidler\n" - "\tCopyright 2009, Haiku, Inc.\n"); -B_TRANSLATE_MARK_VOID("Ok"); -B_TRANSLATE_MARK_VOID("Open Speedstep preferences" B_UTF8_ELLIPSIS); -B_TRANSLATE_MARK_VOID("Quit"); - -// messages FrequencySwitcher -const uint32 kMsgDynamicPolicyPulse = '&dpp'; - -// messages menu -const uint32 kMsgPolicyDynamic = 'pody'; -const uint32 kMsgPolicyPerformance = 'popr'; -const uint32 kMsgPolicyLowEnergy = 'pole'; -const uint32 kMsgPolicySetState = 'poss'; - -// messages StatusView -const uint32 kMsgOpenSSPreferences = 'ossp'; -const char* kDeskbarItemName = "CPUFreqStatusView"; - - -FrequencySwitcher::FrequencySwitcher(CPUFreqDriverInterface* interface, - BHandler* target) - : - BMessageFilter(B_PROGRAMMED_DELIVERY, B_ANY_SOURCE), - fDriverInterface(interface), - fTarget(target), - fMessageRunner(NULL), - fCurrentFrequency(NULL), - fDynamicPolicyStarted(false) -{ -} - - -FrequencySwitcher::~FrequencySwitcher() -{ - freq_preferences dummyPref; - _StartDynamicPolicy(false, dummyPref); -} - - -filter_result -FrequencySwitcher::Filter(BMessage* message, BHandler** target) -{ - filter_result result = B_DISPATCH_MESSAGE; - if (message->what == kMsgDynamicPolicyPulse) { - _CalculateDynamicState(); - result = B_SKIP_MESSAGE; - } - return result; -} - - -void -FrequencySwitcher::SetMode(const freq_preferences& pref) -{ - int16 stateCount = fDriverInterface->GetNumberOfFrequencyStates(); - StateList* list = fDriverInterface->GetCpuFrequencyStates(); - freq_info* currentState = fDriverInterface->GetCurrentFrequencyState(); - freq_info* state = NULL; - bool isDynamic = false; - - switch (pref.mode) { - case DYNAMIC: - isDynamic = true; - fSteppingThreshold = pref.stepping_threshold; - if (fMessageRunner && fIntegrationTime != pref.integration_time) { - fIntegrationTime = pref.integration_time; - fMessageRunner->SetInterval(fIntegrationTime); - } - if (!fDynamicPolicyStarted) - _StartDynamicPolicy(true, pref); - break; - - case PERFORMANCE: - state = list->ItemAt(int32(0)); - if (state != currentState) - fDriverInterface->SetFrequencyState(state); - break; - - case LOW_ENERGIE: - state = list->ItemAt(stateCount - 1); - if (state != currentState) - fDriverInterface->SetFrequencyState(state); - break; - - case CUSTOM: - if (pref.custom_stepping < stateCount) { - state = list->ItemAt(pref.custom_stepping); - fDriverInterface->SetFrequencyState(state); - } - break; - } - - if (!isDynamic && fDynamicPolicyStarted) { - fDynamicPolicyStarted = false; - _StartDynamicPolicy(false, pref); - } -} - - -void -FrequencySwitcher::_CalculateDynamicState() -{ - system_info sysInfo; - get_system_info(&sysInfo); - bigtime_t now = system_time(); - bigtime_t activeTime = sysInfo.cpu_infos[0].active_time; - - // if the dynamic mode is not started first init the prev values - if (!fDynamicPolicyStarted) { - fPrevActiveTime = activeTime; - fPrevTime = now; - fDynamicPolicyStarted = true; - } else { - float usage = (float)(activeTime - fPrevActiveTime ) - / (now - fPrevTime); - if (usage >= 1.0) - usage = 0.9999999; - - int32 numberOfStates = fDriverInterface->GetNumberOfFrequencyStates(); - for (int i = 0; i < numberOfStates; i++) { - float usageOfStep = ColorStepView::UsageOfStep(i, numberOfStates, - fSteppingThreshold); - - if (usage < usageOfStep) { - StateList* list = fDriverInterface->GetCpuFrequencyStates(); - freq_info* newState = list->ItemAt(numberOfStates - 1 - i); - if (newState != fCurrentFrequency) { - LOG("change freq\n"); - fDriverInterface->SetFrequencyState(newState); - fCurrentFrequency = newState; - } - break; - } - } - fPrevActiveTime = activeTime; - fPrevTime = now; - } -} - - -void -FrequencySwitcher::_StartDynamicPolicy(bool start, const freq_preferences& pref) -{ - if (start) { - if (!fMessageRunner) { - fIntegrationTime = pref.integration_time; - fMessageRunner = new BMessageRunner(fTarget, - new BMessage(kMsgDynamicPolicyPulse), pref.integration_time, -1); - fCurrentFrequency = fDriverInterface->GetCurrentFrequencyState(); - } - } else { - delete fMessageRunner; - fMessageRunner = NULL; - } -} - - -// #pragma mark - - - -FrequencyMenu::FrequencyMenu(BMenu* menu, BHandler* target, - PreferencesStorage* storage, - CPUFreqDriverInterface* interface) - : BMessageFilter(B_PROGRAMMED_DELIVERY, B_LOCAL_SOURCE), - fTarget(target), - fStorage(storage), - fInterface(interface) -{ - fDynamicPerformance = new BMenuItem( - B_TRANSLATE("Dynamic performance"), - new BMessage(kMsgPolicyDynamic)); - fHighPerformance = new BMenuItem( - B_TRANSLATE("High performance"), - new BMessage(kMsgPolicyPerformance)); - fLowEnergie = new BMenuItem(B_TRANSLATE("Low energy"), - new BMessage(kMsgPolicyLowEnergy)); - - menu->AddItem(fDynamicPerformance); - menu->AddItem(fHighPerformance); - menu->AddItem(fLowEnergie); - - fCustomStateMenu = new BMenu(B_TRANSLATE("Set state")); - - StateList* stateList = fInterface->GetCpuFrequencyStates(); - for (int i = 0; i < stateList->CountItems(); i++) { - freq_info* info = stateList->ItemAt(i); - BString label; - label << info->frequency; - label += " MHz"; - fCustomStateMenu->AddItem(new BMenuItem(label.String(), - new BMessage(kMsgPolicySetState))); - } - - menu->AddItem(fCustomStateMenu); - - // set the target of the items - fDynamicPerformance->SetTarget(fTarget); - fHighPerformance->SetTarget(fTarget); - fLowEnergie->SetTarget(fTarget); - - fCustomStateMenu->SetTargetForItems(fTarget); -} - - -inline void -FrequencyMenu::_SetL1MenuLabelFrom(BMenuItem* item) -{ - BMenuItem* superItem, *markedItem; - superItem = item->Menu()->Superitem(); - if (superItem) - superItem->SetLabel(item->Label()); - markedItem = item->Menu()->FindMarked(); - if (markedItem) - markedItem->SetMarked(false); - item->SetMarked(true); -} - - -filter_result -FrequencyMenu::Filter(BMessage* msg, BHandler** target) -{ - filter_result result = B_DISPATCH_MESSAGE; - - BMenuItem* item, *superItem, *markedItem; - msg->FindPointer("source", (void**)&item); - if (!item) - return result; - - bool safeChanges = false; - freq_preferences* pref = fStorage->GetPreferences(); - - switch (msg->what) { - case kMsgPolicyDynamic: - pref->mode = DYNAMIC; - _SetL1MenuLabelFrom(item); - safeChanges = true; - msg->what = kUpdatedPreferences; - break; - - case kMsgPolicyPerformance: - pref->mode = PERFORMANCE; - _SetL1MenuLabelFrom(item); - safeChanges = true; - msg->what = kUpdatedPreferences; - break; - - case kMsgPolicyLowEnergy: - pref->mode = LOW_ENERGIE; - _SetL1MenuLabelFrom(item); - safeChanges = true; - msg->what = kUpdatedPreferences; - break; - - case kMsgPolicySetState: - pref->mode = CUSTOM; - pref->custom_stepping = item->Menu()->IndexOf(item); - - superItem = item->Menu()->Supermenu()->Superitem(); - if (superItem) - superItem->SetLabel(item->Label()); - markedItem = item->Menu()->Supermenu()->FindMarked(); - if (markedItem) - markedItem->SetMarked(false); - markedItem = item->Menu()->FindMarked(); - if (markedItem) - markedItem->SetMarked(false); - item->SetMarked(true); - - safeChanges = true; - msg->what = kUpdatedPreferences; - break; - } - - if (safeChanges) - fStorage->SavePreferences(); - - return result; -} - - -void -FrequencyMenu::UpdateMenu() -{ - freq_preferences* pref = fStorage->GetPreferences(); - switch (pref->mode) { - case DYNAMIC: - _SetL1MenuLabelFrom(fDynamicPerformance); - break; - - case PERFORMANCE: - _SetL1MenuLabelFrom(fHighPerformance); - break; - - case LOW_ENERGIE: - _SetL1MenuLabelFrom(fLowEnergie); - break; - - case CUSTOM: - { - BMenuItem* markedItem = fCustomStateMenu->FindMarked(); - if (markedItem) - markedItem->SetMarked(false); - BMenuItem* customItem - = fCustomStateMenu->ItemAt(pref->custom_stepping); - if (customItem) - customItem->SetMarked(true); - BMenuItem* superItem = fCustomStateMenu->Supermenu()->Superitem(); - if (superItem && customItem) - superItem->SetLabel(customItem->Label()); - break; - } - } -} - - -// #pragma mark - - - -StatusView::StatusView(BRect frame, bool inDeskbar, - PreferencesStorage* storage) - : - BView(frame, kDeskbarItemName, B_FOLLOW_LEFT | B_FOLLOW_TOP, - B_WILL_DRAW | B_FRAME_EVENTS), - fInDeskbar(inDeskbar), - fCurrentFrequency(NULL), - fDragger(NULL) -{ - if (!inDeskbar) { - // we were obviously added to a standard window - let's add a dragger - BRect bounds = Bounds(); - bounds.top = bounds.bottom - 7; - bounds.left = bounds.right - 7; - fDragger = new BDragger(bounds, this, - B_FOLLOW_NONE); - AddChild(fDragger); - } - - if (storage) { - fOwningStorage = false; - fStorage = storage; - } else { - fOwningStorage = true; - fStorage = new PreferencesStorage("CPUFrequency", - kDefaultPreferences); - } - - _Init(); -} - - -StatusView::StatusView(BMessage* archive) - : BView(archive), - fInDeskbar(false), - fCurrentFrequency(NULL), - fDragger(NULL) -{ - app_info info; - if (be_app->GetAppInfo(&info) == B_OK - && !strcasecmp(info.signature, "application/x-vnd.Be-TSKB")) - fInDeskbar = true; - - fOwningStorage = true; - fStorage = new PreferencesStorage(kPreferencesFileName, - kDefaultPreferences); - _Init(); -} - - -StatusView::~StatusView() -{ - if (fOwningStorage) - delete fStorage; -} - - -void -StatusView::_AboutRequested() -{ - BAlert *alert = new BAlert("about", B_TRANSLATE("CPUFrequency\n" - "\twritten by Clemens Zeidler\n" - "\tCopyright 2009, Haiku, Inc.\n"), - B_TRANSLATE("OK")); - BTextView *view = alert->TextView(); - BFont font; - - view->SetStylable(true); - - view->GetFont(&font); - font.SetSize(18); - font.SetFace(B_BOLD_FACE); - view->SetFontAndColor(0, 13, &font); - - alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); - alert->Go(); -} - - -void -StatusView::_Quit() -{ - if (fInDeskbar) { - BDeskbar deskbar; - deskbar.RemoveItem(kDeskbarItemName); - } else - be_app->PostMessage(B_QUIT_REQUESTED); -} - - -StatusView* -StatusView::Instantiate(BMessage* archive) -{ - if (!validate_instantiation(archive, "StatusView")) - return NULL; - - return new StatusView(archive); -} - - -status_t -StatusView::Archive(BMessage* archive, bool deep) const -{ - status_t status = BView::Archive(archive, deep); - if (status == B_OK) - status = archive->AddString("add_on", kPrefSignature); - if (status == B_OK) - status = archive->AddString("class", "StatusView"); - - return status; -} - - -void -StatusView::AttachedToWindow() -{ - BView::AttachedToWindow(); - if (Parent()) { - if ((Parent()->Flags() & B_DRAW_ON_CHILDREN) != 0) - SetViewColor(B_TRANSPARENT_COLOR); - else - SetViewColor(Parent()->ViewColor()); - } else - SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); - - SetLowColor(ViewColor()); - - // watching if the driver change the frequency - fDriverInterface.StartWatching(this); - - // monitor preferences file - fPrefFileWatcher = new PrefFileWatcher(fStorage, this); - AddFilter(fPrefFileWatcher); - - // FrequencySwitcher - fFrequencySwitcher = new FrequencySwitcher(&fDriverInterface, this); - fFrequencySwitcher->SetMode(*(fStorage->GetPreferences())); - AddFilter(fFrequencySwitcher); - - // perferences menu - fPreferencesMenu = new BPopUpMenu(B_EMPTY_STRING, false, false); - fPreferencesMenuFilter = new FrequencyMenu(fPreferencesMenu, this, - fStorage, &fDriverInterface); - - fPreferencesMenu->SetFont(be_plain_font); - - fPreferencesMenu->AddSeparatorItem(); - fOpenPrefItem = new BMenuItem(B_TRANSLATE( - "Open Speedstep preferences" B_UTF8_ELLIPSIS), - new BMessage(kMsgOpenSSPreferences)); - fPreferencesMenu->AddItem(fOpenPrefItem); - fOpenPrefItem->SetTarget(this); - - if (fInDeskbar) { - fQuitItem= new BMenuItem(B_TRANSLATE("Quit"), - new BMessage(B_QUIT_REQUESTED)); - fPreferencesMenu->AddItem(fQuitItem); - fQuitItem->SetTarget(this); - } - AddFilter(fPreferencesMenuFilter); - - fPreferencesMenuFilter->UpdateMenu(); -} - - -void -StatusView::DetachedFromWindow() -{ - fDriverInterface.StopWatching(); - - if (RemoveFilter(fPrefFileWatcher)) - delete fPrefFileWatcher; - if (RemoveFilter(fFrequencySwitcher)) - delete fFrequencySwitcher; - if (RemoveFilter(fPreferencesMenuFilter)) - delete fPreferencesMenuFilter; - delete fPreferencesMenu; -} - - -void -StatusView::MessageReceived(BMessage* message) -{ - switch (message->what) { - case kMsgOpenSSPreferences: - _OpenPreferences(); - break; - - case kMSGFrequencyChanged: - message->FindPointer("freq_info", (void**)&fCurrentFrequency); - _SetupNewFreqString(); - Invalidate(); - break; - - case kUpdatedPreferences: - fFrequencySwitcher->SetMode(*(fStorage->GetPreferences())); - fPreferencesMenuFilter->UpdateMenu(); - break; - - case B_ABOUT_REQUESTED: - _AboutRequested(); - break; - - case B_QUIT_REQUESTED: - _Quit(); - break; - - default: - BView::MessageReceived(message); - } -} - - -void -StatusView::FrameResized(float width, float height) -{ - Invalidate(); -} - - -void -StatusView::Draw(BRect updateRect) -{ - font_height fontHeight; - GetFontHeight(&fontHeight); - float height = fontHeight.ascent + fontHeight.descent; - - if (be_control_look != NULL) { - be_control_look->DrawLabel(this, fFreqString.String(), - Parent()->ViewColor(), 0, BPoint(0, height)); - } else { - MovePenTo(0, height); - DrawString(fFreqString.String()); - } -} - - - - -void -StatusView::MouseDown(BPoint point) -{ - if (fShowPopUpMenu) { - ConvertToScreen(&point); - fPreferencesMenu->Go(point, true, false, true); - } -} - - -void -StatusView::GetPreferredSize(float *width, float *height) -{ - font_height fontHeight; - GetFontHeight(&fontHeight); - *height = fontHeight.ascent + fontHeight.descent; - if (!fInDeskbar) - *height += 7; - - *width = StringWidth(MAX_FREQ_STRING); -} - - -void -StatusView::ResizeToPreferred(void) -{ - float width, height; - GetPreferredSize(&width, &height); - ResizeTo(width, height); -} - - -void -StatusView::ShowPopUpMenu(bool show) -{ - fShowPopUpMenu = show; -} - - -void -StatusView::UpdateCPUFreqState() -{ - fFrequencySwitcher->SetMode(*(fStorage->GetPreferences())); -} - - -void -StatusView::_Init() -{ - fShowPopUpMenu = true; - fCurrentFrequency = fDriverInterface.GetCurrentFrequencyState(); - - _SetupNewFreqString(); -} - - -void -StatusView::_SetupNewFreqString() -{ - if (fCurrentFrequency) { - fFreqString = ColorStepView::CreateFrequencyString( - fCurrentFrequency->frequency); - } else - fFreqString = "? MHz"; - - ResizeToPreferred(); - - if (fDragger) { - BRect bounds = Bounds(); - fDragger->MoveTo(bounds.right - 7, bounds.bottom - 7); - } -} - -void -StatusView::_OpenPreferences() -{ - status_t ret = be_roster->Launch(kPrefSignature); - if (ret == B_ALREADY_RUNNING) { - app_info info; - ret = be_roster->GetAppInfo(kPrefSignature, &info); - if (ret == B_OK) - ret = be_roster->ActivateApp(info.team); - } - if (ret < B_OK) { - BString errorMessage(B_TRANSLATE( - "Launching the CPU frequency preflet failed.\n\nError: ")); - errorMessage << strerror(ret); - BAlert* alert = new BAlert("launch error", errorMessage.String(), - "OK"); - // asynchronous alert in order to not block replicant host - // application - alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); - alert->Go(NULL); - } -} - - -// #pragma mark - - - -extern "C" _EXPORT BView* -instantiate_deskbar_item(void) -{ - return new StatusView(BRect(0, 0, 15, 15), true, NULL); -} diff --git a/src/preferences/cpufrequency/StatusView.h b/src/preferences/cpufrequency/StatusView.h deleted file mode 100644 index cc677c182b..0000000000 --- a/src/preferences/cpufrequency/StatusView.h +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright 2009, Haiku, Inc. All Rights Reserved. - * Distributed under the terms of the MIT License. - * - * Authors: - * Clemens Zeidler, haiku@clemens-zeidler.de - */ -#ifndef STATUS_VIEW_H -#define STATUS_VIEW_H - - -#include -#include -#include -#include -#include - -#include "CPUFrequencyView.h" -#include "DriverInterface.h" -#include "PreferencesWindow.h" - - -extern const char* kDeskbarItemName; -extern const char* kAddonSignature; - - -class FrequencySwitcher : public BMessageFilter { -public: - FrequencySwitcher( - CPUFreqDriverInterface* interface, - BHandler* target); - virtual ~FrequencySwitcher(); - - virtual filter_result Filter(BMessage* message, BHandler** _target); - - void SetMode(const freq_preferences& pref); - -private: - void _CalculateDynamicState(); - void _StartDynamicPolicy(bool start, - const freq_preferences& pref); - - CPUFreqDriverInterface* fDriverInterface; - BHandler* fTarget; - BMessageRunner* fMessageRunner; - - freq_info* fCurrentFrequency; - - bool fDynamicPolicyStarted; - bigtime_t fPrevActiveTime; - bigtime_t fPrevTime; - float fSteppingThreshold; - bigtime_t fIntegrationTime; -}; - - -class FrequencyMenu : public BMessageFilter { -public: - FrequencyMenu(BMenu* menu, BHandler* target, - PreferencesStorage* - storage, - CPUFreqDriverInterface* interface); - virtual filter_result Filter(BMessage* message, BHandler** _target); - - void UpdateMenu(); - -private: - inline void _SetL1MenuLabelFrom(BMenuItem* item); - - BHandler* fTarget; - BMenuItem* fDynamicPerformance; - BMenuItem* fHighPerformance; - BMenuItem* fLowEnergie; - BMenu* fCustomStateMenu; - - PreferencesStorage* fStorage; - CPUFreqDriverInterface* fInterface; -}; - - -class StatusView : public BView { -public: - StatusView(BRect frame, bool inDeskbar = false, - PreferencesStorage* - storage = NULL); - StatusView(BMessage* archive); - virtual ~StatusView(); - - static StatusView* Instantiate(BMessage* archive); - virtual status_t Archive(BMessage* archive, - bool deep = true) const; - - virtual void AttachedToWindow(); - virtual void DetachedFromWindow(); - - virtual void MessageReceived(BMessage* message); - virtual void FrameResized(float width, float height); - virtual void MouseDown(BPoint where); - virtual void Draw(BRect updateRect); - - virtual void GetPreferredSize(float *width, float *height); - virtual void ResizeToPreferred(void); - - virtual void ShowPopUpMenu(bool show = true); - - virtual void UpdateCPUFreqState(); - -private: - void _Init(); - void _SetupNewFreqString(); - void _OpenPreferences(); - void _AboutRequested(); - void _Quit(); - - bool fInDeskbar; - - CPUFreqDriverInterface fDriverInterface; - freq_info* fCurrentFrequency; - FrequencySwitcher* fFrequencySwitcher; - - bool fShowPopUpMenu; - BPopUpMenu* fPreferencesMenu; - BMenuItem* fOpenPrefItem; - BMenuItem* fQuitItem; - - FrequencyMenu* fPreferencesMenuFilter; - bool fOwningStorage; - PreferencesStorage* fStorage; - PrefFileWatcher* fPrefFileWatcher; - - BString fFreqString; - BDragger* fDragger; -}; - -#endif // STATUS_VIEW_H diff --git a/src/preferences/cpufrequency/cpufrequency.rdef b/src/preferences/cpufrequency/cpufrequency.rdef deleted file mode 100644 index 2aa9100ae6..0000000000 --- a/src/preferences/cpufrequency/cpufrequency.rdef +++ /dev/null @@ -1,45 +0,0 @@ - -resource app_signature "application/x-vnd.Haiku-CPUFrequencyPref"; - -resource app_name_catalog_entry "x-vnd.Haiku-CPUFrequencyPref:System name:CPUFrequency"; - -resource app_version { - major = 1, - middle = 0, - minor = 0, - - variety = B_APPV_FINAL, - internal = 0, - - short_info = "CPUFrequency", - long_info = "CPUFrequency ©2008-2009 Haiku, Inc." -}; - -resource app_flags B_SINGLE_LAUNCH; - -resource vector_icon { - $"6E6369660E03010000020002023980000000000000004000004BE00008908100" - $"010000FFFF01000000020016023CC7EE389BC0BA16573E39B04977C842ADC700" - $"FFFFD3020006023C529D3753A2B8966F3D9D084B6044496AAF00474747FFA5A0" - $"A002001602BC4E76BC411B3C90DABCA00D47587D4ABA850090FFD40200160238" - $"313C3B5CF0BFCD963C7AAC4C13943FCAF901ECFFC3054B04017E020006033E2F" - $"99387F17BA42DB3FF5B94A0E32482C90001D1E2C3D454658FF01010102000602" - $"3879063B8224BE2CC83B10DB4A1F6F49B894FF9A9A9A00242222020006033C69" - $"A60000000000003E186148800049800058F3F3F300D4CECEFFD9D9D902000603" - $"3C1F1A33E78CB7ACC03FFE4F48BB3EBD7B6C0078D905818CFF05FF7ADD050200" - $"1602349C2E37B5FABA1F6036FC624A3E004B320001D3FF910200160235777837" - $"0A67B7E8CE363A844A1D684B45D800F3FF2E0D0A04486050605C51544E04033E" - $"5349594856475C49604B5C4E604B0A06262A264C485E5252523030240A04262A" - $"4838523030240A044838485E525252300A04262A264C485E48380A04453A4553" - $"2844282E0A04B6F9C0F42845282EB701B8EC0A044550455328452AC0F30A0445" - $"3A45502A43B701B8EC0408AEBAB6BCBCC32FBD4F2E3930BDA8B9ACC0A5BA9EBC" - $"03BB1EBFD937BF0DBD4FC072BCC3C019BDDBC0CB46460204BF23C726BF91C70D" - $"BEB5C73FBE9FC87EBE7AC7D9BEC5C922BFAAC97BBF3CC994C018C962C02DC823" - $"C053C8C8C008C77F0204BFCEC6FBC042C6E0BF5BC715BF48C85ABF1FC7B3BF71" - $"C902C063C95ABFF0C974C0D7C93FC0EAC7FAC113C8A2C0C1C7530E0A07010000" - $"0A0101011001178300040A0001021001178400040A020103000A080109000A0B" - $"010A1001178120040A030104000A04020506000A090107000A0A0108000A0D01" - $"0C0815FF0A0C010B0815FF0A0D010C0A3FEAF70000000000003FEAF7C573B4C2" - $"770615FF0A0C010B0A3FEAF70000000000003FEAF7C573B4C2770615FF" -}; - diff --git a/src/preferences/cpufrequency/main.cpp b/src/preferences/cpufrequency/main.cpp deleted file mode 100644 index f24d576241..0000000000 --- a/src/preferences/cpufrequency/main.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2009, Haiku, Inc. All Rights Reserved. - * Distributed under the terms of the MIT License. - * - * Authors: - * Clemens Zeidler, haiku@clemens-zeidler.de - */ - - -#include -#include -#include - -#include "CPUFrequencyView.h" -#include "PreferencesWindow.h" - - -#undef B_TRANSLATION_CONTEXT -#define B_TRANSLATION_CONTEXT "Main window" - - -int -main(int argc, char* argv[]) -{ - BApplication *app = new BApplication(kPrefSignature); - - PreferencesWindow *window; - window = new PreferencesWindow( - B_TRANSLATE_SYSTEM_NAME("CPUFrequency"), kPreferencesFileName, - kDefaultPreferences); - CPUFrequencyView* prefView - = new CPUFrequencyView(BRect(0, 0, 400, 350), window); - window->SetPreferencesView(prefView); - window->Show(); - app->Run(); - - delete app; - return 0; -} diff --git a/src/preferences/mail/DNSQuery.cpp b/src/preferences/mail/DNSQuery.cpp index d54c7a6ec8..0869701172 100644 --- a/src/preferences/mail/DNSQuery.cpp +++ b/src/preferences/mail/DNSQuery.cpp @@ -19,7 +19,7 @@ #endif -static vint32 gID = 1; +static int32 gID = 1; BRawNetBuffer::BRawNetBuffer() diff --git a/src/preferences/virtualmemory/SettingsWindow.cpp b/src/preferences/virtualmemory/SettingsWindow.cpp index 38bf127c48..508cf46060 100644 --- a/src/preferences/virtualmemory/SettingsWindow.cpp +++ b/src/preferences/virtualmemory/SettingsWindow.cpp @@ -476,11 +476,12 @@ SettingsWindow::_Update() void SettingsWindow::_UpdateSwapInfo() { - system_memory_info memInfo = {}; - __get_system_info_etc(B_MEMORY_INFO, &memInfo, sizeof(memInfo)); + system_info info; + get_system_info(&info); - off_t currentSwapSize = memInfo.max_swap_space; - off_t currentSwapUsed = (memInfo.max_swap_space - memInfo.free_swap_space); + off_t currentSwapSize = info.max_swap_pages * B_PAGE_SIZE; + off_t currentSwapUsed + = (info.max_swap_pages - info.free_swap_pages) * B_PAGE_SIZE; char sizeStr[16]; BString swapSizeStr = string_for_size(currentSwapSize, sizeStr, diff --git a/src/servers/app/drawing/Painter/Painter.cpp b/src/servers/app/drawing/Painter/Painter.cpp index 98b043a9dc..1f45f4e0a8 100644 --- a/src/servers/app/drawing/Painter/Painter.cpp +++ b/src/servers/app/drawing/Painter/Painter.cpp @@ -125,7 +125,7 @@ detect_simd() // supported across all CPUs found. uint32 systemSIMD = 0xffffffff; - for (int32 cpu = 0; cpu < systemInfo.cpu_count; cpu++) { + for (uint32 cpu = 0; cpu < systemInfo.cpu_count; cpu++) { cpuid_info cpuInfo; get_cpuid(&cpuInfo, 0, cpu); diff --git a/src/servers/media/DefaultManager.h b/src/servers/media/DefaultManager.h index 33a78c01e6..826b31d063 100644 --- a/src/servers/media/DefaultManager.h +++ b/src/servers/media/DefaultManager.h @@ -74,7 +74,7 @@ private: uint32 fBeginHeader[3]; uint32 fEndHeader[3]; thread_id fRescanThread; - vint32 fRescanRequested; + int32 fRescanRequested; BLocker fRescanLock; }; diff --git a/src/servers/print/PrintServerApp.h b/src/servers/print/PrintServerApp.h index 55e8447d99..3c242aac0b 100644 --- a/src/servers/print/PrintServerApp.h +++ b/src/servers/print/PrintServerApp.h @@ -89,7 +89,7 @@ class PrintServerApp : public BApplication, public FolderListener { BBitmap *fSelectedIconMini; BBitmap *fSelectedIconLarge; #endif - vint32 fReferences; + int32 fReferences; sem_id fHasReferences; Settings *fSettings; bool fUseConfigWindow; diff --git a/src/servers/print/Printer.h b/src/servers/print/Printer.h index 07dbff878f..c15b676837 100644 --- a/src/servers/print/Printer.h +++ b/src/servers/print/Printer.h @@ -110,7 +110,7 @@ private: // the next job to process Job* fJob; // the current nmber of processing threads - vint32 fProcessing; + int32 fProcessing; // stop processing bool fAbort; static BObjectList sPrinters; diff --git a/src/servers/registrar/mime/RegistrarThreadManager.h b/src/servers/registrar/mime/RegistrarThreadManager.h index e111bcde54..6dcc59ccd5 100644 --- a/src/servers/registrar/mime/RegistrarThreadManager.h +++ b/src/servers/registrar/mime/RegistrarThreadManager.h @@ -39,7 +39,7 @@ private: std::list::iterator& RemoveThread(std::list::iterator &i); std::list fThreads; - vint32 fThreadCount; + int32 fThreadCount; }; #endif // THREAD_MANAGER_H diff --git a/src/system/boot/platform/bios_ia32/cpu.cpp b/src/system/boot/platform/bios_ia32/cpu.cpp index e9d405b883..cc70cbaba9 100644 --- a/src/system/boot/platform/bios_ia32/cpu.cpp +++ b/src/system/boot/platform/bios_ia32/cpu.cpp @@ -327,7 +327,7 @@ check_cpu_features() } cpuid_info info; - if (get_current_cpuid(&info, 1) != B_OK) + if (get_current_cpuid(&info, 1, 0) != B_OK) return B_ERROR; if ((info.eax_1.features & RDTSC_FEATURE) == 0) { diff --git a/src/system/boot/platform/bios_ia32/interrupts.cpp b/src/system/boot/platform/bios_ia32/interrupts.cpp index 2d5d0fa596..92f6d6f7f9 100644 --- a/src/system/boot/platform/bios_ia32/interrupts.cpp +++ b/src/system/boot/platform/bios_ia32/interrupts.cpp @@ -96,7 +96,8 @@ set_interrupt_gate(int n, void (*function)()) if (n >= DEBUG_IDT_SLOT_COUNT) return; - sDebugIDT[n].a = (KERNEL_CODE_SEG << 16) | (0x0000ffff & (addr_t)function); + sDebugIDT[n].a + = (KERNEL_CODE_SELECTOR << 16) | (0x0000ffff & (addr_t)function); sDebugIDT[n].b = (0xffff0000 & (addr_t)function) | 0x8e00; } diff --git a/src/system/boot/platform/bios_ia32/long.cpp b/src/system/boot/platform/bios_ia32/long.cpp index d632efc970..990bcdd546 100644 --- a/src/system/boot/platform/bios_ia32/long.cpp +++ b/src/system/boot/platform/bios_ia32/long.cpp @@ -74,13 +74,13 @@ long_gdt_init() clear_segment_descriptor(&gdt[0]); // Set up code/data segments (TSS segments set up later in the kernel). - set_segment_descriptor(&gdt[KERNEL_CODE_SEG / 8], DT_CODE_EXECUTE_ONLY, + set_segment_descriptor(&gdt[KERNEL_CODE_SEGMENT], DT_CODE_EXECUTE_ONLY, DPL_KERNEL); - set_segment_descriptor(&gdt[KERNEL_DATA_SEG / 8], DT_DATA_WRITEABLE, + set_segment_descriptor(&gdt[KERNEL_DATA_SEGMENT], DT_DATA_WRITEABLE, DPL_KERNEL); - set_segment_descriptor(&gdt[USER_CODE_SEG / 8], DT_CODE_EXECUTE_ONLY, + set_segment_descriptor(&gdt[USER_CODE_SEGMENT], DT_CODE_EXECUTE_ONLY, DPL_USER); - set_segment_descriptor(&gdt[USER_DATA_SEG / 8], DT_DATA_WRITEABLE, + set_segment_descriptor(&gdt[USER_DATA_SEGMENT], DT_DATA_WRITEABLE, DPL_USER); // Used by long_enter_kernel(). @@ -330,7 +330,7 @@ long_start_kernel() { // Check whether long mode is supported. cpuid_info info; - get_current_cpuid(&info, 0x80000001); + get_current_cpuid(&info, 0x80000001, 0); if ((info.regs.edx & (1 << 29)) == 0) panic("64-bit kernel requires a 64-bit CPU"); diff --git a/src/system/boot/platform/bios_ia32/long_asm.S b/src/system/boot/platform/bios_ia32/long_asm.S index 72b30c26cf..0ee9b8e9be 100644 --- a/src/system/boot/platform/bios_ia32/long_asm.S +++ b/src/system/boot/platform/bios_ia32/long_asm.S @@ -58,12 +58,12 @@ FUNCTION(long_enter_kernel): movl %ecx, %cr0 // Jump into the 64-bit code segment. - ljmp $KERNEL_CODE_SEG, $.Llmode + ljmp $KERNEL_CODE_SELECTOR, $.Llmode .align 8 .code64 .Llmode: // Set data segments. - mov $KERNEL_DATA_SEG, %ax + mov $KERNEL_DATA_SELECTOR, %ax mov %ax, %ss xor %ax, %ax mov %ax, %ds diff --git a/src/system/boot/platform/bios_ia32/mmu.cpp b/src/system/boot/platform/bios_ia32/mmu.cpp index 93eaed5423..8bfe21ec09 100644 --- a/src/system/boot/platform/bios_ia32/mmu.cpp +++ b/src/system/boot/platform/bios_ia32/mmu.cpp @@ -577,20 +577,20 @@ mmu_init_for_kernel(void) clear_segment_descriptor(&virtualGDT[0]); // seg 0x08 - kernel 4GB code - set_segment_descriptor(&virtualGDT[1], 0, 0xffffffff, DT_CODE_READABLE, - DPL_KERNEL); + set_segment_descriptor(&virtualGDT[KERNEL_CODE_SEGMENT], 0, 0xffffffff, + DT_CODE_READABLE, DPL_KERNEL); // seg 0x10 - kernel 4GB data - set_segment_descriptor(&virtualGDT[2], 0, 0xffffffff, DT_DATA_WRITEABLE, - DPL_KERNEL); + set_segment_descriptor(&virtualGDT[KERNEL_DATA_SEGMENT], 0, 0xffffffff, + DT_DATA_WRITEABLE, DPL_KERNEL); // seg 0x1b - ring 3 user 4GB code - set_segment_descriptor(&virtualGDT[3], 0, 0xffffffff, DT_CODE_READABLE, - DPL_USER); + set_segment_descriptor(&virtualGDT[USER_CODE_SEGMENT], 0, 0xffffffff, + DT_CODE_READABLE, DPL_USER); // seg 0x23 - ring 3 user 4GB data - set_segment_descriptor(&virtualGDT[4], 0, 0xffffffff, DT_DATA_WRITEABLE, - DPL_USER); + set_segment_descriptor(&virtualGDT[USER_DATA_SEGMENT], 0, 0xffffffff, + DT_DATA_WRITEABLE, DPL_USER); // virtualGDT[5] and above will be filled later by the kernel // to contain the TSS descriptors, and for TLS (one for every CPU) diff --git a/src/system/boot/platform/bios_ia32/smp.cpp b/src/system/boot/platform/bios_ia32/smp.cpp index 138e1cd21a..9a2e77ea01 100644 --- a/src/system/boot/platform/bios_ia32/smp.cpp +++ b/src/system/boot/platform/bios_ia32/smp.cpp @@ -158,9 +158,9 @@ smp_do_mp_config(mp_floating_struct *floatingStruct) = (struct mp_base_processor *)pointer; pointer += sizeof(struct mp_base_processor); - if (gKernelArgs.num_cpus == MAX_BOOT_CPUS) { - TRACE(("smp: already reached maximum boot CPUs (%d)\n", - MAX_BOOT_CPUS)); + if (gKernelArgs.num_cpus == SMP_MAX_CPUS) { + TRACE(("smp: already reached maximum CPUs (%d)\n", + SMP_MAX_CPUS)); continue; } @@ -277,9 +277,9 @@ smp_do_acpi_config(void) switch (apic->type) { case ACPI_MADT_LOCAL_APIC: { - if (gKernelArgs.num_cpus == MAX_BOOT_CPUS) { - TRACE(("smp: already reached maximum boot CPUs (%d)\n", - MAX_BOOT_CPUS)); + if (gKernelArgs.num_cpus == SMP_MAX_CPUS) { + TRACE(("smp: already reached maximum CPUs (%d)\n", + SMP_MAX_CPUS)); break; } @@ -581,7 +581,7 @@ smp_add_safemode_menus(Menu *menu) item->SetHelpText("Disables using the local APIC, also disables SMP."); cpuid_info info; - if (get_current_cpuid(&info, 1) == B_OK + if (get_current_cpuid(&info, 1, 0) == B_OK && (info.regs.ecx & IA32_FEATURE_EXT_X2APIC) != 0) { #if 0 menu->AddItem(item = new(nothrow) MenuItem("Disable X2APIC")); @@ -617,7 +617,7 @@ smp_init(void) #endif cpuid_info info; - if (get_current_cpuid(&info, 1) != B_OK) + if (get_current_cpuid(&info, 1, 0) != B_OK) return; if ((info.eax_1.features & IA32_FEATURE_APIC) == 0) { diff --git a/src/system/kernel/DPC.cpp b/src/system/kernel/DPC.cpp index 7d64ca4a84..4d7261663c 100644 --- a/src/system/kernel/DPC.cpp +++ b/src/system/kernel/DPC.cpp @@ -158,7 +158,7 @@ DPCQueue::Close(bool cancelPending) status_t -DPCQueue::Add(DPCCallback* callback, bool schedulerLocked) +DPCQueue::Add(DPCCallback* callback) { // queue the callback, if the queue isn't closed already InterruptsSpinLocker locker(fLock); @@ -174,14 +174,14 @@ DPCQueue::Add(DPCCallback* callback, bool schedulerLocked) // notify the condition variable, if necessary if (wasEmpty) - fPendingCallbacksCondition.NotifyAll(schedulerLocked); + fPendingCallbacksCondition.NotifyAll(); return B_OK; } status_t -DPCQueue::Add(void (*function)(void*), void* argument, bool schedulerLocked) +DPCQueue::Add(void (*function)(void*), void* argument) { if (function == NULL) return B_BAD_VALUE; @@ -201,7 +201,7 @@ DPCQueue::Add(void (*function)(void*), void* argument, bool schedulerLocked) functionCallback->SetTo(function, argument); // add it - status_t error = Add(functionCallback, schedulerLocked); + status_t error = Add(functionCallback); if (error != B_OK) Recycle(functionCallback); diff --git a/src/system/kernel/Jamfile b/src/system/kernel/Jamfile index 551317d75b..1ed3b2f278 100644 --- a/src/system/kernel/Jamfile +++ b/src/system/kernel/Jamfile @@ -62,10 +62,12 @@ KernelMergeObject kernel_core.o : user_mutex.cpp # scheduler + low_latency.cpp + power_saving.cpp scheduler.cpp - scheduler_affine.cpp - scheduler_simple.cpp - scheduler_simple_smp.cpp + scheduler_cpu.cpp + scheduler_profiler.cpp + scheduler_thread.cpp scheduler_tracing.cpp scheduling_analysis.cpp diff --git a/src/system/kernel/UserEvent.cpp b/src/system/kernel/UserEvent.cpp index 7d890d9cf5..f0c49b6f58 100644 --- a/src/system/kernel/UserEvent.cpp +++ b/src/system/kernel/UserEvent.cpp @@ -27,32 +27,30 @@ struct SignalEvent::EventSignal : Signal { pid_t sendingProcess) : Signal(number, signalCode, errorCode, sendingProcess), - fInUse(false) + fInUse(0) { } - bool IsInUse() const + bool MarkUsed() { - return fInUse; + return atomic_get_and_set(&fInUse, 1) != 0; } - void SetInUse(bool inUse) + void SetUnused() { - fInUse = inUse; + // mark not-in-use + atomic_set(&fInUse, 0); } virtual void Handled() { - // mark not-in-use - InterruptsSpinLocker schedulerLocker(gSchedulerLock); - fInUse = false; - schedulerLocker.Unlock(); + SetUnused(); Signal::Handled(); } private: - bool fInUse; + int32 fInUse; }; @@ -111,20 +109,21 @@ TeamSignalEvent::Create(Team* team, uint32 signalNumber, int32 signalCode, status_t TeamSignalEvent::Fire() { - // called with the scheduler lock held - if (fSignal->IsInUse()) + if (fSignal->MarkUsed()) return B_BUSY; fSignal->AcquireReference(); // one reference is transferred to send_signal_to_team_locked + + InterruptsSpinLocker locker(fTeam->signal_lock); status_t error = send_signal_to_team_locked(fTeam, fSignal->Number(), fSignal, B_DO_NOT_RESCHEDULE); - if (error == B_OK) { - // Mark the signal in-use. There are situations (for certain signals), - // in which send_signal_to_team_locked() succeeds without queuing the - // signal. - fSignal->SetInUse(fSignal->IsPending()); - } + locker.Unlock(); + + // There are situations (for certain signals), in which + // send_signal_to_team_locked() succeeds without queuing the signal. + if (error != B_OK || !fSignal->IsPending()) + fSignal->SetUnused(); return error; } @@ -165,20 +164,22 @@ ThreadSignalEvent::Create(Thread* thread, uint32 signalNumber, int32 signalCode, status_t ThreadSignalEvent::Fire() { - // called with the scheduler lock held - if (fSignal->IsInUse()) + if (fSignal->MarkUsed()) return B_BUSY; fSignal->AcquireReference(); // one reference is transferred to send_signal_to_team_locked + InterruptsReadSpinLocker teamLocker(fThread->team_lock); + SpinLocker locker(fThread->team->signal_lock); status_t error = send_signal_to_thread_locked(fThread, fSignal->Number(), fSignal, B_DO_NOT_RESCHEDULE); - if (error == B_OK) { - // Mark the signal in-use. There are situations (for certain signals), - // in which send_signal_to_team_locked() succeeds without queuing the - // signal. - fSignal->SetInUse(fSignal->IsPending()); - } + locker.Unlock(); + teamLocker.Unlock(); + + // There are situations (for certain signals), in which + // send_signal_to_team_locked() succeeds without queuing the signal. + if (error != B_OK || !fSignal->IsPending()) + fSignal->SetUnused(); return error; } @@ -190,7 +191,7 @@ ThreadSignalEvent::Fire() CreateThreadEvent::CreateThreadEvent(const ThreadCreationAttributes& attributes) : fCreationAttributes(attributes), - fPendingDPC(false) + fPendingDPC(0) { // attributes.name is a pointer to a temporary buffer. Copy the name into // our own buffer and replace the name pointer. @@ -216,12 +217,11 @@ CreateThreadEvent::Create(const ThreadCreationAttributes& attributes) status_t CreateThreadEvent::Fire() { - if (fPendingDPC) + bool wasPending = atomic_get_and_set(&fPendingDPC, 1) != 0; + if (wasPending) return B_BUSY; - fPendingDPC = true; - - DPCQueue::DefaultQueue(B_NORMAL_PRIORITY)->Add(this, true); + DPCQueue::DefaultQueue(B_NORMAL_PRIORITY)->Add(this); return B_OK; } @@ -231,10 +231,7 @@ void CreateThreadEvent::DoDPC(DPCQueue* queue) { // We're no longer queued in the DPC queue, so we can be reused. - { - InterruptsSpinLocker schedulerLocker(gSchedulerLock); - fPendingDPC = false; - } + atomic_set(&fPendingDPC, 0); // create the thread thread_id threadID = thread_create_thread(fCreationAttributes, false); diff --git a/src/system/kernel/UserTimer.cpp b/src/system/kernel/UserTimer.cpp index 8c0cabec15..db816a426f 100644 --- a/src/system/kernel/UserTimer.cpp +++ b/src/system/kernel/UserTimer.cpp @@ -29,6 +29,8 @@ static const bigtime_t kMinPeriodicTimerInterval = 100; static RealTimeUserTimerList sAbsoluteRealTimeTimers; static spinlock sAbsoluteRealTimeTimersLock = B_SPINLOCK_INITIALIZER; +static seqlock sUserTimerLock = B_SEQLOCK_INITIALIZER; + // #pragma mark - TimerLocker @@ -116,7 +118,8 @@ UserTimer::UserTimer() fNextTime(0), fInterval(0), fOverrunCount(0), - fScheduled(false) + fScheduled(false), + fSkip(0) { // mark the timer unused fTimer.user_data = this; @@ -134,8 +137,6 @@ UserTimer::~UserTimer() Cancels the timer, if it is already scheduled, and optionally schedules it with new parameters. - The caller must not hold the scheduler lock. - \param nextTime The time at which the timer should go off the next time. If \c B_INFINITE_TIMEOUT, the timer will not be scheduled. Whether the value is interpreted as absolute or relative time, depends on \c flags. @@ -157,8 +158,6 @@ UserTimer::~UserTimer() /*! Cancels the timer, if it is scheduled. - - The caller must not hold the scheduler lock. */ void UserTimer::Cancel() @@ -173,8 +172,6 @@ UserTimer::Cancel() uint32& _overrunCount) Return information on the current timer. - The caller must not hold the scheduler lock. - \param _remainingTime Return variable that will be set to the microseconds remaining to the time for which the timer was scheduled next before the call. If it wasn't scheduled, the variable is set to @@ -191,7 +188,22 @@ UserTimer::Cancel() /*static*/ int32 UserTimer::HandleTimerHook(struct timer* timer) { - ((UserTimer*)timer->user_data)->HandleTimer(); + UserTimer* userTimer = reinterpret_cast(timer->user_data); + + InterruptsLocker _; + + bool locked = false; + while (!locked && atomic_get(&userTimer->fSkip) == 0) { + locked = try_acquire_write_seqlock(&sUserTimerLock); + if (!locked) + cpu_pause(); + } + + if (locked) { + userTimer->HandleTimer(); + release_write_seqlock(&sUserTimerLock); + } + return B_HANDLED_INTERRUPT; } @@ -218,7 +230,7 @@ UserTimer::HandleTimer() /*! Updates the start time for a periodic timer after it expired, enforcing sanity limits and updating \c fOverrunCount, if necessary. - The caller must not hold the scheduler lock. + The caller must not hold \c sUserTimerLock. */ void UserTimer::UpdatePeriodicStartTime() @@ -242,7 +254,7 @@ UserTimer::UpdatePeriodicStartTime() /*! Checks whether the timer start time lies too much in the past and, if so, adjusts it and updates \c fOverrunCount. - The caller must not hold the scheduler lock. + The caller must not hold \c sUserTimerLock. \param now The current time. */ @@ -264,6 +276,17 @@ UserTimer::CheckPeriodicOverrun(bigtime_t now) } +void +UserTimer::CancelTimer() +{ + ASSERT(fScheduled); + + atomic_set(&fSkip, 1); + cancel_timer(&fTimer); + atomic_set(&fSkip, 0); +} + + // #pragma mark - SystemTimeUserTimer @@ -271,14 +294,14 @@ void SystemTimeUserTimer::Schedule(bigtime_t nextTime, bigtime_t interval, uint32 flags, bigtime_t& _oldRemainingTime, bigtime_t& _oldInterval) { - InterruptsSpinLocker schedulerLocker(gSchedulerLock); + InterruptsWriteSequentialLocker locker(sUserTimerLock); // get the current time bigtime_t now = system_time(); // Cancel the old timer, if still scheduled, and get the previous values. if (fScheduled) { - cancel_timer(&fTimer); + CancelTimer(); _oldRemainingTime = fNextTime - now; _oldInterval = fInterval; @@ -308,17 +331,20 @@ void SystemTimeUserTimer::GetInfo(bigtime_t& _remainingTime, bigtime_t& _interval, uint32& _overrunCount) { - InterruptsSpinLocker schedulerLocker(gSchedulerLock); + uint32 count; + do { + count = acquire_read_seqlock(&sUserTimerLock); - if (fScheduled) { - _remainingTime = fNextTime - system_time(); - _interval = fInterval; - } else { - _remainingTime = B_INFINITE_TIMEOUT; - _interval = 0; - } + if (fScheduled) { + _remainingTime = fNextTime - system_time(); + _interval = fInterval; + } else { + _remainingTime = B_INFINITE_TIMEOUT; + _interval = 0; + } - _overrunCount = fOverrunCount; + _overrunCount = fOverrunCount; + } while (!release_read_seqlock(&sUserTimerLock, count)); } @@ -337,7 +363,7 @@ SystemTimeUserTimer::HandleTimer() /*! Schedules the kernel timer. - The caller must hold the scheduler lock. + The caller must hold \c sUserTimerLock. \param now The current system time to be used. \param checkPeriodicOverrun If \c true, calls CheckPeriodicOverrun() first, @@ -352,9 +378,7 @@ SystemTimeUserTimer::ScheduleKernelTimer(bigtime_t now, CheckPeriodicOverrun(now); uint32 timerFlags = B_ONE_SHOT_ABSOLUTE_TIMER - | B_TIMER_USE_TIMER_STRUCT_TIMES | B_TIMER_ACQUIRE_SCHEDULER_LOCK; - // We use B_TIMER_ACQUIRE_SCHEDULER_LOCK to avoid race conditions - // between setting/canceling the timer and the event handler. + | B_TIMER_USE_TIMER_STRUCT_TIMES; fTimer.schedule_time = std::max(fNextTime, (bigtime_t)0); fTimer.period = 0; @@ -372,14 +396,14 @@ void RealTimeUserTimer::Schedule(bigtime_t nextTime, bigtime_t interval, uint32 flags, bigtime_t& _oldRemainingTime, bigtime_t& _oldInterval) { - InterruptsSpinLocker schedulerLocker(gSchedulerLock); + InterruptsWriteSequentialLocker locker(sUserTimerLock); // get the current time bigtime_t now = system_time(); // Cancel the old timer, if still scheduled, and get the previous values. if (fScheduled) { - cancel_timer(&fTimer); + CancelTimer(); _oldRemainingTime = fNextTime - now; _oldInterval = fInterval; @@ -425,7 +449,7 @@ RealTimeUserTimer::Schedule(bigtime_t nextTime, bigtime_t interval, /*! Called when the real-time clock has been changed. - The caller must hold the scheduler lock. Optionally the caller may also + The caller must hold \c sUserTimerLock. Optionally the caller may also hold \c sAbsoluteRealTimeTimersLock. */ void @@ -440,7 +464,7 @@ RealTimeUserTimer::TimeWarped() return; // cancel the kernel timer and reschedule it - cancel_timer(&fTimer); + CancelTimer(); fNextTime += oldRealTimeOffset - fRealTimeOffset; @@ -482,7 +506,8 @@ void TeamTimeUserTimer::Schedule(bigtime_t nextTime, bigtime_t interval, uint32 flags, bigtime_t& _oldRemainingTime, bigtime_t& _oldInterval) { - InterruptsSpinLocker schedulerLocker(gSchedulerLock); + InterruptsWriteSequentialLocker locker(sUserTimerLock); + SpinLocker timeLocker(fTeam != NULL ? &fTeam->time_lock : NULL); // get the current time, but only if needed bool nowValid = fTeam != NULL; @@ -491,7 +516,7 @@ TeamTimeUserTimer::Schedule(bigtime_t nextTime, bigtime_t interval, // Cancel the old timer, if still scheduled, and get the previous values. if (fTeam != NULL) { if (fScheduled) { - cancel_timer(&fTimer); + CancelTimer(); fScheduled = false; } @@ -516,9 +541,13 @@ TeamTimeUserTimer::Schedule(bigtime_t nextTime, bigtime_t interval, // Get the team. If it doesn't exist anymore, just don't schedule the // timer anymore. - fTeam = Team::Get(fTeamID); - if (fTeam == NULL) + Team* newTeam = Team::Get(fTeamID); + if (newTeam == NULL) { + fTeam = NULL; return; + } else if (fTeam == NULL) + timeLocker.SetTo(newTeam->time_lock, false); + fTeam = newTeam; fAbsolute = (flags & B_RELATIVE_TIMEOUT) == 0; @@ -540,23 +569,27 @@ void TeamTimeUserTimer::GetInfo(bigtime_t& _remainingTime, bigtime_t& _interval, uint32& _overrunCount) { - InterruptsSpinLocker schedulerLocker(gSchedulerLock); + uint32 count; + do { + count = acquire_read_seqlock(&sUserTimerLock); - if (fTeam != NULL) { - _remainingTime = fNextTime - fTeam->CPUTime(false); - _interval = fInterval; - } else { - _remainingTime = B_INFINITE_TIMEOUT; - _interval = 0; - } + if (fTeam != NULL) { + InterruptsSpinLocker timeLocker(fTeam->time_lock); + _remainingTime = fNextTime - fTeam->CPUTime(false); + _interval = fInterval; + } else { + _remainingTime = B_INFINITE_TIMEOUT; + _interval = 0; + } - _overrunCount = fOverrunCount; + _overrunCount = fOverrunCount; + } while (!release_read_seqlock(&sUserTimerLock, count)); } /*! Deactivates the timer, if it is activated. - The caller must hold the scheduler lock. + The caller must hold \c time_lock and \c sUserTimerLock. */ void TeamTimeUserTimer::Deactivate() @@ -566,7 +599,7 @@ TeamTimeUserTimer::Deactivate() // unschedule, if scheduled if (fScheduled) { - cancel_timer(&fTimer); + CancelTimer(); fScheduled = false; } @@ -584,7 +617,7 @@ TeamTimeUserTimer::Deactivate() was just set. Schedules a kernel timer for the remaining time, respectively cancels it. - The caller must hold the scheduler lock. + The caller must hold \c time_lock and \c sUserTimerLock. \param unscheduledThread If not \c NULL, this is the thread that is currently running and which is in the process of being unscheduled. @@ -611,7 +644,7 @@ TeamTimeUserTimer::Update(Thread* unscheduledThread) /*! Called when the team's CPU time clock which this timer refers to has been set. - The caller must hold the scheduler lock. + The caller must hold \c time_lock and \c sUserTimerLock. \param changedBy The value by which the clock has changed. */ @@ -654,7 +687,7 @@ TeamTimeUserTimer::HandleTimer() /*! Schedules/cancels the kernel timer as necessary. \c fRunningThreads must be up-to-date. - The caller must hold the scheduler lock. + The caller must hold \c time_lock and \c sUserTimerLock. \param unscheduling \c true, when the current thread is in the process of being unscheduled. @@ -664,7 +697,7 @@ TeamTimeUserTimer::_Update(bool unscheduling) { // unschedule the kernel timer, if scheduled if (fScheduled) - cancel_timer(&fTimer); + CancelTimer(); // if no more threads are running, we're done if (fRunningThreads == 0) { @@ -692,10 +725,7 @@ TeamTimeUserTimer::_Update(bool unscheduling) // rounding errors. add_timer(&fTimer, &HandleTimerHook, fTimer.schedule_time, - B_ONE_SHOT_ABSOLUTE_TIMER | B_TIMER_USE_TIMER_STRUCT_TIMES - | B_TIMER_ACQUIRE_SCHEDULER_LOCK); - // We use B_TIMER_ACQUIRE_SCHEDULER_LOCK to avoid race conditions - // between setting/canceling the timer and the event handler. + B_ONE_SHOT_ABSOLUTE_TIMER | B_TIMER_USE_TIMER_STRUCT_TIMES); // We use B_TIMER_USE_TIMER_STRUCT_TIMES, so period remains 0, which // our base class expects. @@ -724,7 +754,8 @@ void TeamUserTimeUserTimer::Schedule(bigtime_t nextTime, bigtime_t interval, uint32 flags, bigtime_t& _oldRemainingTime, bigtime_t& _oldInterval) { - InterruptsSpinLocker schedulerLocker(gSchedulerLock); + InterruptsWriteSequentialLocker locker(sUserTimerLock); + SpinLocker timeLocker(fTeam != NULL ? &fTeam->time_lock : NULL); // get the current time, but only if needed bool nowValid = fTeam != NULL; @@ -753,9 +784,13 @@ TeamUserTimeUserTimer::Schedule(bigtime_t nextTime, bigtime_t interval, // Get the team. If it doesn't exist anymore, just don't schedule the // timer anymore. - fTeam = Team::Get(fTeamID); - if (fTeam == NULL) + Team* newTeam = Team::Get(fTeamID); + if (newTeam == NULL) { + fTeam = NULL; return; + } else if (fTeam == NULL) + timeLocker.SetTo(newTeam->time_lock, false); + fTeam = newTeam; // convert relative to absolute timeouts if ((flags & B_RELATIVE_TIMEOUT) != 0) { @@ -775,23 +810,27 @@ void TeamUserTimeUserTimer::GetInfo(bigtime_t& _remainingTime, bigtime_t& _interval, uint32& _overrunCount) { - InterruptsSpinLocker schedulerLocker(gSchedulerLock); + uint32 count; + do { + count = acquire_read_seqlock(&sUserTimerLock); - if (fTeam != NULL) { - _remainingTime = fNextTime - fTeam->UserCPUTime(); - _interval = fInterval; - } else { - _remainingTime = B_INFINITE_TIMEOUT; - _interval = 0; - } + if (fTeam != NULL) { + InterruptsSpinLocker timeLocker(fTeam->time_lock); + _remainingTime = fNextTime - fTeam->UserCPUTime(); + _interval = fInterval; + } else { + _remainingTime = B_INFINITE_TIMEOUT; + _interval = 0; + } - _overrunCount = fOverrunCount; + _overrunCount = fOverrunCount; + } while (!release_read_seqlock(&sUserTimerLock, count)); } /*! Deactivates the timer, if it is activated. - The caller must hold the scheduler lock. + The caller must hold \c time_lock and \c sUserTimerLock. */ void TeamUserTimeUserTimer::Deactivate() @@ -808,7 +847,7 @@ TeamUserTimeUserTimer::Deactivate() /*! Checks whether the timer is up, firing an event, if so. - The caller must hold the scheduler lock. + The caller must hold \c time_lock and \c sUserTimerLock. */ void TeamUserTimeUserTimer::Check() @@ -861,7 +900,8 @@ void ThreadTimeUserTimer::Schedule(bigtime_t nextTime, bigtime_t interval, uint32 flags, bigtime_t& _oldRemainingTime, bigtime_t& _oldInterval) { - InterruptsSpinLocker schedulerLocker(gSchedulerLock); + InterruptsWriteSequentialLocker locker(sUserTimerLock); + SpinLocker timeLocker(fThread->time_lock); // get the current time, but only if needed bool nowValid = fThread != NULL; @@ -870,7 +910,7 @@ ThreadTimeUserTimer::Schedule(bigtime_t nextTime, bigtime_t interval, // Cancel the old timer, if still scheduled, and get the previous values. if (fThread != NULL) { if (fScheduled) { - cancel_timer(&fTimer); + CancelTimer(); fScheduled = false; } @@ -895,9 +935,13 @@ ThreadTimeUserTimer::Schedule(bigtime_t nextTime, bigtime_t interval, // Get the thread. If it doesn't exist anymore, just don't schedule the // timer anymore. - fThread = Thread::Get(fThreadID); - if (fThread == NULL) + Thread* newThread = Thread::Get(fThreadID); + if (newThread == NULL) { + fThread = NULL; return; + } else if (fThread == NULL) + timeLocker.SetTo(newThread->time_lock, false); + fThread = newThread; fAbsolute = (flags & B_RELATIVE_TIMEOUT) == 0; @@ -920,23 +964,27 @@ void ThreadTimeUserTimer::GetInfo(bigtime_t& _remainingTime, bigtime_t& _interval, uint32& _overrunCount) { - InterruptsSpinLocker schedulerLocker(gSchedulerLock); + uint32 count; + do { + count = acquire_read_seqlock(&sUserTimerLock); - if (fThread != NULL) { - _remainingTime = fNextTime - fThread->CPUTime(false); - _interval = fInterval; - } else { - _remainingTime = B_INFINITE_TIMEOUT; - _interval = 0; - } + if (fThread != NULL) { + SpinLocker timeLocker(fThread->time_lock); + _remainingTime = fNextTime - fThread->CPUTime(false); + _interval = fInterval; + } else { + _remainingTime = B_INFINITE_TIMEOUT; + _interval = 0; + } - _overrunCount = fOverrunCount; + _overrunCount = fOverrunCount; + } while (!release_read_seqlock(&sUserTimerLock, count)); } /*! Deactivates the timer, if it is activated. - The caller must hold the scheduler lock. + The caller must hold \c time_lock and \c sUserTimerLock. */ void ThreadTimeUserTimer::Deactivate() @@ -946,7 +994,7 @@ ThreadTimeUserTimer::Deactivate() // unschedule, if scheduled if (fScheduled) { - cancel_timer(&fTimer); + CancelTimer(); fScheduled = false; } @@ -963,7 +1011,7 @@ ThreadTimeUserTimer::Deactivate() scheduled, or, when the timer was just set and the thread is already running. Schedules a kernel timer for the remaining time. - The caller must hold the scheduler lock. + The caller must hold \c time_lock and \c sUserTimerLock. */ void ThreadTimeUserTimer::Start() @@ -989,11 +1037,7 @@ ThreadTimeUserTimer::Start() fTimer.schedule_time = 0; fTimer.period = 0; - uint32 flags = B_ONE_SHOT_ABSOLUTE_TIMER - | B_TIMER_USE_TIMER_STRUCT_TIMES | B_TIMER_ACQUIRE_SCHEDULER_LOCK; - // We use B_TIMER_ACQUIRE_SCHEDULER_LOCK to avoid race conditions - // between setting/canceling the timer and the event handler. - + uint32 flags = B_ONE_SHOT_ABSOLUTE_TIMER | B_TIMER_USE_TIMER_STRUCT_TIMES; add_timer(&fTimer, &HandleTimerHook, fTimer.schedule_time, flags); fScheduled = true; @@ -1005,7 +1049,7 @@ ThreadTimeUserTimer::Start() Called when the thread whose CPU time is referred to by the timer is unscheduled, or, when the timer is canceled. - The caller must hold the scheduler lock. + The caller must hold \c sUserTimerLock. */ void ThreadTimeUserTimer::Stop() @@ -1016,7 +1060,7 @@ ThreadTimeUserTimer::Stop() ASSERT(fScheduled); // cancel the kernel timer - cancel_timer(&fTimer); + CancelTimer(); fScheduled = false; // TODO: To avoid odd race conditions, we should check the current time of @@ -1028,7 +1072,7 @@ ThreadTimeUserTimer::Stop() /*! Called when the team's CPU time clock which this timer refers to has been set. - The caller must hold the scheduler lock. + The caller must hold \c time_lock and \c sUserTimerLock. \param changedBy The value by which the clock has changed. */ @@ -1320,7 +1364,7 @@ create_timer(clockid_t clockID, int32 timerID, Team* team, Thread* thread, /*! Called when the CPU time clock of the given thread has been set. - The caller must hold the scheduler lock. + The caller must hold \c time_lock. \param thread The thread whose CPU time clock has been set. \param changedBy The value by which the CPU time clock has changed @@ -1339,7 +1383,7 @@ thread_clock_changed(Thread* thread, bigtime_t changedBy) /*! Called when the CPU time clock of the given team has been set. - The caller must hold the scheduler lock. + The caller must hold \c time_lock. \param team The team whose CPU time clock has been set. \param changedBy The value by which the CPU time clock has changed @@ -1439,7 +1483,7 @@ user_timer_get_clock(clockid_t clockID, bigtime_t& _time) case CLOCK_THREAD_CPUTIME_ID: { Thread* thread = thread_get_current_thread(); - InterruptsSpinLocker schedulerLocker(gSchedulerLock); + InterruptsSpinLocker timeLocker(thread->time_lock); _time = thread->CPUTime(false); return B_OK; } @@ -1447,7 +1491,7 @@ user_timer_get_clock(clockid_t clockID, bigtime_t& _time) case CLOCK_PROCESS_USER_CPUTIME_ID: { Team* team = thread_get_current_thread()->team; - InterruptsSpinLocker schedulerLocker(gSchedulerLock); + InterruptsSpinLocker timeLocker(team->time_lock); _time = team->UserCPUTime(); return B_OK; } @@ -1475,7 +1519,7 @@ user_timer_get_clock(clockid_t clockID, bigtime_t& _time) BReference teamReference(team, true); // get the time - InterruptsSpinLocker schedulerLocker(gSchedulerLock); + InterruptsSpinLocker timeLocker(team->time_lock); _time = team->CPUTime(false); return B_OK; @@ -1488,7 +1532,7 @@ void user_timer_real_time_clock_changed() { // we need to update all absolute real-time timers - InterruptsSpinLocker schedulerLocker(gSchedulerLock); + InterruptsWriteSequentialLocker locker(sUserTimerLock); SpinLocker globalListLocker(sAbsoluteRealTimeTimersLock); for (RealTimeUserTimerList::Iterator it @@ -1592,7 +1636,7 @@ _user_set_clock(clockid_t clockID, bigtime_t time) case CLOCK_THREAD_CPUTIME_ID: { Thread* thread = thread_get_current_thread(); - InterruptsSpinLocker schedulerLocker(gSchedulerLock); + InterruptsSpinLocker timeLocker(thread->time_lock); bigtime_t diff = time - thread->CPUTime(false); thread->cpu_clock_offset += diff; @@ -1627,7 +1671,7 @@ _user_set_clock(clockid_t clockID, bigtime_t time) BReference teamReference(team, true); // set the time offset - InterruptsSpinLocker schedulerLocker(gSchedulerLock); + InterruptsSpinLocker timeLocker(team->time_lock); bigtime_t diff = time - team->CPUTime(false); team->cpu_clock_offset += diff; diff --git a/src/system/kernel/arch/x86/32/apm.cpp b/src/system/kernel/arch/x86/32/apm.cpp index 1c6b72b178..c5174485da 100644 --- a/src/system/kernel/arch/x86/32/apm.cpp +++ b/src/system/kernel/arch/x86/32/apm.cpp @@ -33,7 +33,6 @@ #define CARRY_FLAG 0x01 -extern segment_descriptor *gGDT; extern void *gDmaAddress; extern addr_t gBiosBase; @@ -314,49 +313,52 @@ apm_init(kernel_args *args) // (the first 640kB are mapped as DMA area in arch_vm_init()). addr_t biosData = (addr_t)gDmaAddress + 0x400; - set_segment_descriptor(&gGDT[BIOS_DATA_SEGMENT >> 3], - biosData, B_PAGE_SIZE - biosData, - DT_DATA_WRITEABLE, DPL_KERNEL); + for (uint32 i = 0; i < args->num_cpus; i++) { + segment_descriptor* gdt = get_gdt(i); - // TODO: test if APM segments really are in the BIOS ROM area (especially the - // data segment) + set_segment_descriptor(&gdt[BIOS_DATA_SEGMENT], biosData, + B_PAGE_SIZE - biosData, DT_DATA_WRITEABLE, DPL_KERNEL); - // Setup APM GDTs + // TODO: test if APM segments really are in the BIOS ROM area + // (especially the data segment) - // We ignore their length, and just set their segments to 64 kB which - // shouldn't cause any headaches + // Setup APM GDTs - set_segment_descriptor(&gGDT[APM_CODE32_SEGMENT >> 3], - gBiosBase + (info.code32_segment_base << 4) - 0xe0000, 0xffff, - DT_CODE_READABLE, DPL_KERNEL); - set_segment_descriptor(&gGDT[APM_CODE16_SEGMENT >> 3], - gBiosBase + (info.code16_segment_base << 4) - 0xe0000, 0xffff, - DT_CODE_READABLE, DPL_KERNEL); - gGDT[APM_CODE16_SEGMENT >> 3].d_b = 0; - // 16-bit segment + // We ignore their length, and just set their segments to 64 kB which + // shouldn't cause any headaches - if ((info.data_segment_base << 4) < 0xe0000) { - // use the BIOS data segment as data segment for APM + set_segment_descriptor(&gdt[APM_CODE32_SEGMENT], + gBiosBase + (info.code32_segment_base << 4) - 0xe0000, 0xffff, + DT_CODE_READABLE, DPL_KERNEL); + set_segment_descriptor(&gdt[APM_CODE16_SEGMENT], + gBiosBase + (info.code16_segment_base << 4) - 0xe0000, 0xffff, + DT_CODE_READABLE, DPL_KERNEL); + gdt[APM_CODE16_SEGMENT].d_b = 0; + // 16-bit segment - if (info.data_segment_length == 0) { - args->platform_args.apm.data_segment_length = B_PAGE_SIZE - - info.data_segment_base; + if ((info.data_segment_base << 4) < 0xe0000) { + // use the BIOS data segment as data segment for APM + + if (info.data_segment_length == 0) { + args->platform_args.apm.data_segment_length = B_PAGE_SIZE + - info.data_segment_base; + } + + set_segment_descriptor(&gdt[APM_DATA_SEGMENT], + (addr_t)gDmaAddress + (info.data_segment_base << 4), + info.data_segment_length, + DT_DATA_WRITEABLE, DPL_KERNEL); + } else { + // use the BIOS area as data segment + set_segment_descriptor(&gdt[APM_DATA_SEGMENT], + gBiosBase + (info.data_segment_base << 4) - 0xe0000, 0xffff, + DT_DATA_WRITEABLE, DPL_KERNEL); } - - set_segment_descriptor(&gGDT[APM_DATA_SEGMENT >> 3], - (addr_t)gDmaAddress + (info.data_segment_base << 4), - info.data_segment_length, - DT_DATA_WRITEABLE, DPL_KERNEL); - } else { - // use the BIOS area as data segment - set_segment_descriptor(&gGDT[APM_DATA_SEGMENT >> 3], - gBiosBase + (info.data_segment_base << 4) - 0xe0000, 0xffff, - DT_DATA_WRITEABLE, DPL_KERNEL); } // setup APM entry point - sAPMBiosEntry.segment = APM_CODE32_SEGMENT; + sAPMBiosEntry.segment = (APM_CODE32_SEGMENT << 3) | DPL_KERNEL; sAPMBiosEntry.offset = info.code32_segment_offset; apm_driver_version(info.version); diff --git a/src/system/kernel/arch/x86/32/cpuid.S b/src/system/kernel/arch/x86/32/cpuid.S index 5eb25731db..0595a4d4f7 100644 --- a/src/system/kernel/arch/x86/32/cpuid.S +++ b/src/system/kernel/arch/x86/32/cpuid.S @@ -11,12 +11,14 @@ .text -/* void get_current_cpuid(cpuid_info *info, uint32 eaxRegister) */ +/* void get_current_cpuid(cpuid_info *info, uint32 eaxRegister, + uint32 ecxRegister) */ FUNCTION(get_current_cpuid): pushl %ebx pushl %edi movl 12(%esp),%edi /* first arg points to the cpuid_info structure */ movl 16(%esp),%eax /* second arg sets up eax */ + movl 20(%esp),%ecx /* third arg sets up ecx */ cpuid movl %eax,0(%edi) /* copy the regs into the cpuid_info structure */ movl %ebx,4(%edi) diff --git a/src/system/kernel/arch/x86/32/descriptors.cpp b/src/system/kernel/arch/x86/32/descriptors.cpp index 465aab78ca..fef30fa3d4 100644 --- a/src/system/kernel/arch/x86/32/descriptors.cpp +++ b/src/system/kernel/arch/x86/32/descriptors.cpp @@ -1,4 +1,5 @@ /* + * Copyright 2013, Paweł Dziepak, pdziepak@quarnos.org. * Copyright 2008-2011, Michael Lotz, mmlr@mlotz.ch. * Copyright 2010, Clemens Zeidler, haiku@clemens-zeidler.de. * Copyright 2009-2011, Ingo Weinhold, ingo_weinhold@gmx.de. @@ -28,16 +29,20 @@ #include "interrupts.h" -static interrupt_descriptor* sIDTs[B_MAX_CPU_COUNT]; +#define IDT_GATES_COUNT 256 + + +typedef interrupt_descriptor interrupt_descriptor_table[IDT_GATES_COUNT]; + +global_descriptor_table gGDTs[SMP_MAX_CPUS]; +static interrupt_descriptor_table sIDTs[SMP_MAX_CPUS]; // table with functions handling respective interrupts typedef void interrupt_handler_function(struct iframe* frame); -static const uint32 kInterruptHandlerTableSize = 256; +static const uint32 kInterruptHandlerTableSize = IDT_GATES_COUNT; interrupt_handler_function* gInterruptHandlerTable[kInterruptHandlerTableSize]; -segment_descriptor* gGDT; - /*! Initializes a descriptor in an IDT. */ @@ -47,7 +52,7 @@ set_gate(interrupt_descriptor *gate_addr, addr_t addr, int type, int dpl) unsigned int gate1; // first byte of gate desc unsigned int gate2; // second byte of gate desc - gate1 = (KERNEL_CODE_SEG << 16) | (0x0000ffff & addr); + gate1 = (KERNEL_CODE_SELECTOR << 16) | (0x0000ffff & addr); gate2 = (0xffff0000 & addr) | 0x8000 | (dpl << 13) | (type << 8); gate_addr->a = gate1; @@ -95,9 +100,9 @@ set_task_gate(int32 cpu, int32 n, int32 segment) static void -load_tss(int cpu) +load_tss() { - short seg = (TSS_SEGMENT(cpu) << 3) | DPL_KERNEL; + short seg = (TSS_SEGMENT << 3) | DPL_KERNEL; asm("ltr %%ax" : : "a" (seg)); } @@ -179,304 +184,389 @@ init_double_fault(int cpuNum) size_t stackSize; tss->sp0 = (addr_t)x86_get_double_fault_stack(cpuNum, &stackSize); tss->sp0 += stackSize; - tss->ss0 = KERNEL_DATA_SEG; + tss->ss0 = KERNEL_DATA_SELECTOR; tss->cr3 = x86_read_cr3(); // copy the current cr3 to the double fault cr3 tss->eip = (uint32)&double_fault; - tss->es = KERNEL_DATA_SEG; - tss->cs = KERNEL_CODE_SEG; - tss->ss = KERNEL_DATA_SEG; + tss->es = KERNEL_DATA_SELECTOR; + tss->cs = KERNEL_CODE_SELECTOR; + tss->ss = KERNEL_DATA_SELECTOR; tss->esp = tss->sp0; - tss->ds = KERNEL_DATA_SEG; - tss->fs = KERNEL_DATA_SEG; - tss->gs = KERNEL_DATA_SEG; + tss->ds = KERNEL_DATA_SELECTOR; + tss->fs = KERNEL_DATA_SELECTOR; + tss->gs = KERNEL_DATA_SELECTOR; tss->ldt_seg_selector = 0; tss->io_map_base = sizeof(struct tss); // add TSS descriptor for this new TSS - uint16 tssSegmentDescriptorIndex = DOUBLE_FAULT_TSS_BASE_SEGMENT + cpuNum; - set_tss_descriptor(&gGDT[tssSegmentDescriptorIndex], - (addr_t)tss, sizeof(struct tss)); + set_tss_descriptor(&gGDTs[cpuNum][DOUBLE_FAULT_TSS_SEGMENT], (addr_t)tss, + sizeof(struct tss)); - set_task_gate(cpuNum, 8, tssSegmentDescriptorIndex << 3); + set_task_gate(cpuNum, 8, DOUBLE_FAULT_TSS_SEGMENT << 3); +} + + +static void +load_gdt(int cpu) +{ + struct { + uint16 limit; + void* address; + } _PACKED gdt_descriptor = { + GDT_SEGMENT_COUNT * sizeof(segment_descriptor) - 1, + gGDTs[cpu] + }; + + asm volatile("lgdt %0" : : "m" (gdt_descriptor)); +} + + +static void +init_gdt_percpu(kernel_args* args, int cpu) +{ + STATIC_ASSERT(GDT_SEGMENT_COUNT <= 8192); + + segment_descriptor* gdt = get_gdt(cpu); + + clear_segment_descriptor(&gdt[0]); + + set_segment_descriptor(&gdt[KERNEL_CODE_SEGMENT], 0, addr_t(-1), + DT_CODE_READABLE, DPL_KERNEL); + set_segment_descriptor(&gdt[KERNEL_DATA_SEGMENT], 0, addr_t(-1), + DT_DATA_WRITEABLE, DPL_KERNEL); + + set_segment_descriptor(&gdt[USER_CODE_SEGMENT], 0, addr_t(-1), + DT_CODE_READABLE, DPL_USER); + set_segment_descriptor(&gdt[USER_DATA_SEGMENT], 0, addr_t(-1), + DT_DATA_WRITEABLE, DPL_USER); + + // initialize the regular and double fault tss stored in the per-cpu + // structure + memset(&gCPU[cpu].arch.tss, 0, sizeof(struct tss)); + gCPU[cpu].arch.tss.ss0 = (KERNEL_DATA_SEGMENT << 3) | DPL_KERNEL; + gCPU[cpu].arch.tss.io_map_base = sizeof(struct tss); + + // add TSS descriptor for this new TSS + set_tss_descriptor(&gdt[TSS_SEGMENT], (addr_t)&gCPU[cpu].arch.tss, + sizeof(struct tss)); + + // initialize the double fault tss + init_double_fault(cpu); + + set_segment_descriptor(&gdt[KERNEL_TLS_SEGMENT], + (addr_t)&gCPU[cpu].arch.kernel_tls, sizeof(void*), DT_DATA_WRITEABLE, + DPL_KERNEL); + set_segment_descriptor(&gdt[USER_TLS_SEGMENT], 0, TLS_SIZE, + DT_DATA_WRITEABLE, DPL_USER); + + load_gdt(cpu); + + load_tss(); + + // set kernel TLS segment + asm volatile("movw %0, %%gs" : : "r" (KERNEL_TLS_SEGMENT << 3)); +} + + +static void +load_idt(int cpu) +{ + struct { + uint16 limit; + void* address; + } _PACKED idt_descriptor = { + IDT_GATES_COUNT * sizeof(interrupt_descriptor) - 1, + &sIDTs[cpu] + }; + + asm volatile("lidt %0" : : "m" (idt_descriptor)); +} + + +static void +init_idt_percpu(kernel_args* args, int cpu) +{ + set_interrupt_gate(cpu, 0, &trap0); + set_interrupt_gate(cpu, 1, &trap1); + set_interrupt_gate(cpu, 2, &trap2); + set_trap_gate(cpu, 3, &trap3); + set_interrupt_gate(cpu, 4, &trap4); + set_interrupt_gate(cpu, 5, &trap5); + set_interrupt_gate(cpu, 6, &trap6); + set_interrupt_gate(cpu, 7, &trap7); + // trap8 (double fault) is set in init_double_fault(). + set_interrupt_gate(cpu, 9, &trap9); + set_interrupt_gate(cpu, 10, &trap10); + set_interrupt_gate(cpu, 11, &trap11); + set_interrupt_gate(cpu, 12, &trap12); + set_interrupt_gate(cpu, 13, &trap13); + set_interrupt_gate(cpu, 14, &trap14); + //set_interrupt_gate(cpu, 15, &trap15); + set_interrupt_gate(cpu, 16, &trap16); + set_interrupt_gate(cpu, 17, &trap17); + set_interrupt_gate(cpu, 18, &trap18); + set_interrupt_gate(cpu, 19, &trap19); + + // legacy or ioapic interrupts + set_interrupt_gate(cpu, 32, &trap32); + set_interrupt_gate(cpu, 33, &trap33); + set_interrupt_gate(cpu, 34, &trap34); + set_interrupt_gate(cpu, 35, &trap35); + set_interrupt_gate(cpu, 36, &trap36); + set_interrupt_gate(cpu, 37, &trap37); + set_interrupt_gate(cpu, 38, &trap38); + set_interrupt_gate(cpu, 39, &trap39); + set_interrupt_gate(cpu, 40, &trap40); + set_interrupt_gate(cpu, 41, &trap41); + set_interrupt_gate(cpu, 42, &trap42); + set_interrupt_gate(cpu, 43, &trap43); + set_interrupt_gate(cpu, 44, &trap44); + set_interrupt_gate(cpu, 45, &trap45); + set_interrupt_gate(cpu, 46, &trap46); + set_interrupt_gate(cpu, 47, &trap47); + + // additional ioapic interrupts + set_interrupt_gate(cpu, 48, &trap48); + set_interrupt_gate(cpu, 49, &trap49); + set_interrupt_gate(cpu, 50, &trap50); + set_interrupt_gate(cpu, 51, &trap51); + set_interrupt_gate(cpu, 52, &trap52); + set_interrupt_gate(cpu, 53, &trap53); + set_interrupt_gate(cpu, 54, &trap54); + set_interrupt_gate(cpu, 55, &trap55); + + // configurable msi or msi-x interrupts + set_interrupt_gate(cpu, 56, &trap56); + set_interrupt_gate(cpu, 57, &trap57); + set_interrupt_gate(cpu, 58, &trap58); + set_interrupt_gate(cpu, 59, &trap59); + set_interrupt_gate(cpu, 60, &trap60); + set_interrupt_gate(cpu, 61, &trap61); + set_interrupt_gate(cpu, 62, &trap62); + set_interrupt_gate(cpu, 63, &trap63); + set_interrupt_gate(cpu, 64, &trap64); + set_interrupt_gate(cpu, 65, &trap65); + set_interrupt_gate(cpu, 66, &trap66); + set_interrupt_gate(cpu, 67, &trap67); + set_interrupt_gate(cpu, 68, &trap68); + set_interrupt_gate(cpu, 69, &trap69); + set_interrupt_gate(cpu, 70, &trap70); + set_interrupt_gate(cpu, 71, &trap71); + set_interrupt_gate(cpu, 72, &trap72); + set_interrupt_gate(cpu, 73, &trap73); + set_interrupt_gate(cpu, 74, &trap74); + set_interrupt_gate(cpu, 75, &trap75); + set_interrupt_gate(cpu, 76, &trap76); + set_interrupt_gate(cpu, 77, &trap77); + set_interrupt_gate(cpu, 78, &trap78); + set_interrupt_gate(cpu, 79, &trap79); + set_interrupt_gate(cpu, 80, &trap80); + set_interrupt_gate(cpu, 81, &trap81); + set_interrupt_gate(cpu, 82, &trap82); + set_interrupt_gate(cpu, 83, &trap83); + set_interrupt_gate(cpu, 84, &trap84); + set_interrupt_gate(cpu, 85, &trap85); + set_interrupt_gate(cpu, 86, &trap86); + set_interrupt_gate(cpu, 87, &trap87); + set_interrupt_gate(cpu, 88, &trap88); + set_interrupt_gate(cpu, 89, &trap89); + set_interrupt_gate(cpu, 90, &trap90); + set_interrupt_gate(cpu, 91, &trap91); + set_interrupt_gate(cpu, 92, &trap92); + set_interrupt_gate(cpu, 93, &trap93); + set_interrupt_gate(cpu, 94, &trap94); + set_interrupt_gate(cpu, 95, &trap95); + set_interrupt_gate(cpu, 96, &trap96); + set_interrupt_gate(cpu, 97, &trap97); + + set_trap_gate(cpu, 98, &trap98); // for performance testing only + set_trap_gate(cpu, 99, &trap99); // syscall interrupt + + // configurable msi or msi-x interrupts + set_interrupt_gate(cpu, 100, &trap100); + set_interrupt_gate(cpu, 101, &trap101); + set_interrupt_gate(cpu, 102, &trap102); + set_interrupt_gate(cpu, 103, &trap103); + set_interrupt_gate(cpu, 104, &trap104); + set_interrupt_gate(cpu, 105, &trap105); + set_interrupt_gate(cpu, 106, &trap106); + set_interrupt_gate(cpu, 107, &trap107); + set_interrupt_gate(cpu, 108, &trap108); + set_interrupt_gate(cpu, 109, &trap109); + set_interrupt_gate(cpu, 110, &trap110); + set_interrupt_gate(cpu, 111, &trap111); + set_interrupt_gate(cpu, 112, &trap112); + set_interrupt_gate(cpu, 113, &trap113); + set_interrupt_gate(cpu, 114, &trap114); + set_interrupt_gate(cpu, 115, &trap115); + set_interrupt_gate(cpu, 116, &trap116); + set_interrupt_gate(cpu, 117, &trap117); + set_interrupt_gate(cpu, 118, &trap118); + set_interrupt_gate(cpu, 119, &trap119); + set_interrupt_gate(cpu, 120, &trap120); + set_interrupt_gate(cpu, 121, &trap121); + set_interrupt_gate(cpu, 122, &trap122); + set_interrupt_gate(cpu, 123, &trap123); + set_interrupt_gate(cpu, 124, &trap124); + set_interrupt_gate(cpu, 125, &trap125); + set_interrupt_gate(cpu, 126, &trap126); + set_interrupt_gate(cpu, 127, &trap127); + set_interrupt_gate(cpu, 128, &trap128); + set_interrupt_gate(cpu, 129, &trap129); + set_interrupt_gate(cpu, 130, &trap130); + set_interrupt_gate(cpu, 131, &trap131); + set_interrupt_gate(cpu, 132, &trap132); + set_interrupt_gate(cpu, 133, &trap133); + set_interrupt_gate(cpu, 134, &trap134); + set_interrupt_gate(cpu, 135, &trap135); + set_interrupt_gate(cpu, 136, &trap136); + set_interrupt_gate(cpu, 137, &trap137); + set_interrupt_gate(cpu, 138, &trap138); + set_interrupt_gate(cpu, 139, &trap139); + set_interrupt_gate(cpu, 140, &trap140); + set_interrupt_gate(cpu, 141, &trap141); + set_interrupt_gate(cpu, 142, &trap142); + set_interrupt_gate(cpu, 143, &trap143); + set_interrupt_gate(cpu, 144, &trap144); + set_interrupt_gate(cpu, 145, &trap145); + set_interrupt_gate(cpu, 146, &trap146); + set_interrupt_gate(cpu, 147, &trap147); + set_interrupt_gate(cpu, 148, &trap148); + set_interrupt_gate(cpu, 149, &trap149); + set_interrupt_gate(cpu, 150, &trap150); + set_interrupt_gate(cpu, 151, &trap151); + set_interrupt_gate(cpu, 152, &trap152); + set_interrupt_gate(cpu, 153, &trap153); + set_interrupt_gate(cpu, 154, &trap154); + set_interrupt_gate(cpu, 155, &trap155); + set_interrupt_gate(cpu, 156, &trap156); + set_interrupt_gate(cpu, 157, &trap157); + set_interrupt_gate(cpu, 158, &trap158); + set_interrupt_gate(cpu, 159, &trap159); + set_interrupt_gate(cpu, 160, &trap160); + set_interrupt_gate(cpu, 161, &trap161); + set_interrupt_gate(cpu, 162, &trap162); + set_interrupt_gate(cpu, 163, &trap163); + set_interrupt_gate(cpu, 164, &trap164); + set_interrupt_gate(cpu, 165, &trap165); + set_interrupt_gate(cpu, 166, &trap166); + set_interrupt_gate(cpu, 167, &trap167); + set_interrupt_gate(cpu, 168, &trap168); + set_interrupt_gate(cpu, 169, &trap169); + set_interrupt_gate(cpu, 170, &trap170); + set_interrupt_gate(cpu, 171, &trap171); + set_interrupt_gate(cpu, 172, &trap172); + set_interrupt_gate(cpu, 173, &trap173); + set_interrupt_gate(cpu, 174, &trap174); + set_interrupt_gate(cpu, 175, &trap175); + set_interrupt_gate(cpu, 176, &trap176); + set_interrupt_gate(cpu, 177, &trap177); + set_interrupt_gate(cpu, 178, &trap178); + set_interrupt_gate(cpu, 179, &trap179); + set_interrupt_gate(cpu, 180, &trap180); + set_interrupt_gate(cpu, 181, &trap181); + set_interrupt_gate(cpu, 182, &trap182); + set_interrupt_gate(cpu, 183, &trap183); + set_interrupt_gate(cpu, 184, &trap184); + set_interrupt_gate(cpu, 185, &trap185); + set_interrupt_gate(cpu, 186, &trap186); + set_interrupt_gate(cpu, 187, &trap187); + set_interrupt_gate(cpu, 188, &trap188); + set_interrupt_gate(cpu, 189, &trap189); + set_interrupt_gate(cpu, 190, &trap190); + set_interrupt_gate(cpu, 191, &trap191); + set_interrupt_gate(cpu, 192, &trap192); + set_interrupt_gate(cpu, 193, &trap193); + set_interrupt_gate(cpu, 194, &trap194); + set_interrupt_gate(cpu, 195, &trap195); + set_interrupt_gate(cpu, 196, &trap196); + set_interrupt_gate(cpu, 197, &trap197); + set_interrupt_gate(cpu, 198, &trap198); + set_interrupt_gate(cpu, 199, &trap199); + set_interrupt_gate(cpu, 200, &trap200); + set_interrupt_gate(cpu, 201, &trap201); + set_interrupt_gate(cpu, 202, &trap202); + set_interrupt_gate(cpu, 203, &trap203); + set_interrupt_gate(cpu, 204, &trap204); + set_interrupt_gate(cpu, 205, &trap205); + set_interrupt_gate(cpu, 206, &trap206); + set_interrupt_gate(cpu, 207, &trap207); + set_interrupt_gate(cpu, 208, &trap208); + set_interrupt_gate(cpu, 209, &trap209); + set_interrupt_gate(cpu, 210, &trap210); + set_interrupt_gate(cpu, 211, &trap211); + set_interrupt_gate(cpu, 212, &trap212); + set_interrupt_gate(cpu, 213, &trap213); + set_interrupt_gate(cpu, 214, &trap214); + set_interrupt_gate(cpu, 215, &trap215); + set_interrupt_gate(cpu, 216, &trap216); + set_interrupt_gate(cpu, 217, &trap217); + set_interrupt_gate(cpu, 218, &trap218); + set_interrupt_gate(cpu, 219, &trap219); + set_interrupt_gate(cpu, 220, &trap220); + set_interrupt_gate(cpu, 221, &trap221); + set_interrupt_gate(cpu, 222, &trap222); + set_interrupt_gate(cpu, 223, &trap223); + set_interrupt_gate(cpu, 224, &trap224); + set_interrupt_gate(cpu, 225, &trap225); + set_interrupt_gate(cpu, 226, &trap226); + set_interrupt_gate(cpu, 227, &trap227); + set_interrupt_gate(cpu, 228, &trap228); + set_interrupt_gate(cpu, 229, &trap229); + set_interrupt_gate(cpu, 230, &trap230); + set_interrupt_gate(cpu, 231, &trap231); + set_interrupt_gate(cpu, 232, &trap232); + set_interrupt_gate(cpu, 233, &trap233); + set_interrupt_gate(cpu, 234, &trap234); + set_interrupt_gate(cpu, 235, &trap235); + set_interrupt_gate(cpu, 236, &trap236); + set_interrupt_gate(cpu, 237, &trap237); + set_interrupt_gate(cpu, 238, &trap238); + set_interrupt_gate(cpu, 239, &trap239); + set_interrupt_gate(cpu, 240, &trap240); + set_interrupt_gate(cpu, 241, &trap241); + set_interrupt_gate(cpu, 242, &trap242); + set_interrupt_gate(cpu, 243, &trap243); + set_interrupt_gate(cpu, 244, &trap244); + set_interrupt_gate(cpu, 245, &trap245); + set_interrupt_gate(cpu, 246, &trap246); + set_interrupt_gate(cpu, 247, &trap247); + set_interrupt_gate(cpu, 248, &trap248); + set_interrupt_gate(cpu, 249, &trap249); + set_interrupt_gate(cpu, 250, &trap250); + + // smp / apic local interrupts + set_interrupt_gate(cpu, 251, &trap251); + set_interrupt_gate(cpu, 252, &trap252); + set_interrupt_gate(cpu, 253, &trap253); + set_interrupt_gate(cpu, 254, &trap254); + set_interrupt_gate(cpu, 255, &trap255); + + load_idt(cpu); } // #pragma mark - +void +x86_descriptors_preboot_init_percpu(kernel_args* args, int cpu) +{ + init_idt_percpu(args, cpu); + init_gdt_percpu(args, cpu); +} + + void x86_descriptors_init(kernel_args* args) { - uint32 i; - interrupt_handler_function** table; - - // Get the GDT and boot CPU IDT set up by the boot loader. - gGDT = (segment_descriptor*)args->arch_args.vir_gdt; - sIDTs[0] = (interrupt_descriptor *)(addr_t)args->arch_args.vir_idt; - - set_interrupt_gate(0, 0, &trap0); - set_interrupt_gate(0, 1, &trap1); - set_interrupt_gate(0, 2, &trap2); - set_trap_gate(0, 3, &trap3); - set_interrupt_gate(0, 4, &trap4); - set_interrupt_gate(0, 5, &trap5); - set_interrupt_gate(0, 6, &trap6); - set_interrupt_gate(0, 7, &trap7); - // trap8 (double fault) is set in init_double_fault(). - set_interrupt_gate(0, 9, &trap9); - set_interrupt_gate(0, 10, &trap10); - set_interrupt_gate(0, 11, &trap11); - set_interrupt_gate(0, 12, &trap12); - set_interrupt_gate(0, 13, &trap13); - set_interrupt_gate(0, 14, &trap14); -// set_interrupt_gate(0, 15, &trap15); - set_interrupt_gate(0, 16, &trap16); - set_interrupt_gate(0, 17, &trap17); - set_interrupt_gate(0, 18, &trap18); - set_interrupt_gate(0, 19, &trap19); - - // legacy or ioapic interrupts - set_interrupt_gate(0, 32, &trap32); - set_interrupt_gate(0, 33, &trap33); - set_interrupt_gate(0, 34, &trap34); - set_interrupt_gate(0, 35, &trap35); - set_interrupt_gate(0, 36, &trap36); - set_interrupt_gate(0, 37, &trap37); - set_interrupt_gate(0, 38, &trap38); - set_interrupt_gate(0, 39, &trap39); - set_interrupt_gate(0, 40, &trap40); - set_interrupt_gate(0, 41, &trap41); - set_interrupt_gate(0, 42, &trap42); - set_interrupt_gate(0, 43, &trap43); - set_interrupt_gate(0, 44, &trap44); - set_interrupt_gate(0, 45, &trap45); - set_interrupt_gate(0, 46, &trap46); - set_interrupt_gate(0, 47, &trap47); - - // additional ioapic interrupts - set_interrupt_gate(0, 48, &trap48); - set_interrupt_gate(0, 49, &trap49); - set_interrupt_gate(0, 50, &trap50); - set_interrupt_gate(0, 51, &trap51); - set_interrupt_gate(0, 52, &trap52); - set_interrupt_gate(0, 53, &trap53); - set_interrupt_gate(0, 54, &trap54); - set_interrupt_gate(0, 55, &trap55); - - // configurable msi or msi-x interrupts - set_interrupt_gate(0, 56, &trap56); - set_interrupt_gate(0, 57, &trap57); - set_interrupt_gate(0, 58, &trap58); - set_interrupt_gate(0, 59, &trap59); - set_interrupt_gate(0, 60, &trap60); - set_interrupt_gate(0, 61, &trap61); - set_interrupt_gate(0, 62, &trap62); - set_interrupt_gate(0, 63, &trap63); - set_interrupt_gate(0, 64, &trap64); - set_interrupt_gate(0, 65, &trap65); - set_interrupt_gate(0, 66, &trap66); - set_interrupt_gate(0, 67, &trap67); - set_interrupt_gate(0, 68, &trap68); - set_interrupt_gate(0, 69, &trap69); - set_interrupt_gate(0, 70, &trap70); - set_interrupt_gate(0, 71, &trap71); - set_interrupt_gate(0, 72, &trap72); - set_interrupt_gate(0, 73, &trap73); - set_interrupt_gate(0, 74, &trap74); - set_interrupt_gate(0, 75, &trap75); - set_interrupt_gate(0, 76, &trap76); - set_interrupt_gate(0, 77, &trap77); - set_interrupt_gate(0, 78, &trap78); - set_interrupt_gate(0, 79, &trap79); - set_interrupt_gate(0, 80, &trap80); - set_interrupt_gate(0, 81, &trap81); - set_interrupt_gate(0, 82, &trap82); - set_interrupt_gate(0, 83, &trap83); - set_interrupt_gate(0, 84, &trap84); - set_interrupt_gate(0, 85, &trap85); - set_interrupt_gate(0, 86, &trap86); - set_interrupt_gate(0, 87, &trap87); - set_interrupt_gate(0, 88, &trap88); - set_interrupt_gate(0, 89, &trap89); - set_interrupt_gate(0, 90, &trap90); - set_interrupt_gate(0, 91, &trap91); - set_interrupt_gate(0, 92, &trap92); - set_interrupt_gate(0, 93, &trap93); - set_interrupt_gate(0, 94, &trap94); - set_interrupt_gate(0, 95, &trap95); - set_interrupt_gate(0, 96, &trap96); - set_interrupt_gate(0, 97, &trap97); - - set_trap_gate(0, 98, &trap98); // for performance testing only - set_trap_gate(0, 99, &trap99); // syscall interrupt - - reserve_io_interrupt_vectors(2, 98); - - // configurable msi or msi-x interrupts - set_interrupt_gate(0, 100, &trap100); - set_interrupt_gate(0, 101, &trap101); - set_interrupt_gate(0, 102, &trap102); - set_interrupt_gate(0, 103, &trap103); - set_interrupt_gate(0, 104, &trap104); - set_interrupt_gate(0, 105, &trap105); - set_interrupt_gate(0, 106, &trap106); - set_interrupt_gate(0, 107, &trap107); - set_interrupt_gate(0, 108, &trap108); - set_interrupt_gate(0, 109, &trap109); - set_interrupt_gate(0, 110, &trap110); - set_interrupt_gate(0, 111, &trap111); - set_interrupt_gate(0, 112, &trap112); - set_interrupt_gate(0, 113, &trap113); - set_interrupt_gate(0, 114, &trap114); - set_interrupt_gate(0, 115, &trap115); - set_interrupt_gate(0, 116, &trap116); - set_interrupt_gate(0, 117, &trap117); - set_interrupt_gate(0, 118, &trap118); - set_interrupt_gate(0, 119, &trap119); - set_interrupt_gate(0, 120, &trap120); - set_interrupt_gate(0, 121, &trap121); - set_interrupt_gate(0, 122, &trap122); - set_interrupt_gate(0, 123, &trap123); - set_interrupt_gate(0, 124, &trap124); - set_interrupt_gate(0, 125, &trap125); - set_interrupt_gate(0, 126, &trap126); - set_interrupt_gate(0, 127, &trap127); - set_interrupt_gate(0, 128, &trap128); - set_interrupt_gate(0, 129, &trap129); - set_interrupt_gate(0, 130, &trap130); - set_interrupt_gate(0, 131, &trap131); - set_interrupt_gate(0, 132, &trap132); - set_interrupt_gate(0, 133, &trap133); - set_interrupt_gate(0, 134, &trap134); - set_interrupt_gate(0, 135, &trap135); - set_interrupt_gate(0, 136, &trap136); - set_interrupt_gate(0, 137, &trap137); - set_interrupt_gate(0, 138, &trap138); - set_interrupt_gate(0, 139, &trap139); - set_interrupt_gate(0, 140, &trap140); - set_interrupt_gate(0, 141, &trap141); - set_interrupt_gate(0, 142, &trap142); - set_interrupt_gate(0, 143, &trap143); - set_interrupt_gate(0, 144, &trap144); - set_interrupt_gate(0, 145, &trap145); - set_interrupt_gate(0, 146, &trap146); - set_interrupt_gate(0, 147, &trap147); - set_interrupt_gate(0, 148, &trap148); - set_interrupt_gate(0, 149, &trap149); - set_interrupt_gate(0, 150, &trap150); - set_interrupt_gate(0, 151, &trap151); - set_interrupt_gate(0, 152, &trap152); - set_interrupt_gate(0, 153, &trap153); - set_interrupt_gate(0, 154, &trap154); - set_interrupt_gate(0, 155, &trap155); - set_interrupt_gate(0, 156, &trap156); - set_interrupt_gate(0, 157, &trap157); - set_interrupt_gate(0, 158, &trap158); - set_interrupt_gate(0, 159, &trap159); - set_interrupt_gate(0, 160, &trap160); - set_interrupt_gate(0, 161, &trap161); - set_interrupt_gate(0, 162, &trap162); - set_interrupt_gate(0, 163, &trap163); - set_interrupt_gate(0, 164, &trap164); - set_interrupt_gate(0, 165, &trap165); - set_interrupt_gate(0, 166, &trap166); - set_interrupt_gate(0, 167, &trap167); - set_interrupt_gate(0, 168, &trap168); - set_interrupt_gate(0, 169, &trap169); - set_interrupt_gate(0, 170, &trap170); - set_interrupt_gate(0, 171, &trap171); - set_interrupt_gate(0, 172, &trap172); - set_interrupt_gate(0, 173, &trap173); - set_interrupt_gate(0, 174, &trap174); - set_interrupt_gate(0, 175, &trap175); - set_interrupt_gate(0, 176, &trap176); - set_interrupt_gate(0, 177, &trap177); - set_interrupt_gate(0, 178, &trap178); - set_interrupt_gate(0, 179, &trap179); - set_interrupt_gate(0, 180, &trap180); - set_interrupt_gate(0, 181, &trap181); - set_interrupt_gate(0, 182, &trap182); - set_interrupt_gate(0, 183, &trap183); - set_interrupt_gate(0, 184, &trap184); - set_interrupt_gate(0, 185, &trap185); - set_interrupt_gate(0, 186, &trap186); - set_interrupt_gate(0, 187, &trap187); - set_interrupt_gate(0, 188, &trap188); - set_interrupt_gate(0, 189, &trap189); - set_interrupt_gate(0, 190, &trap190); - set_interrupt_gate(0, 191, &trap191); - set_interrupt_gate(0, 192, &trap192); - set_interrupt_gate(0, 193, &trap193); - set_interrupt_gate(0, 194, &trap194); - set_interrupt_gate(0, 195, &trap195); - set_interrupt_gate(0, 196, &trap196); - set_interrupt_gate(0, 197, &trap197); - set_interrupt_gate(0, 198, &trap198); - set_interrupt_gate(0, 199, &trap199); - set_interrupt_gate(0, 200, &trap200); - set_interrupt_gate(0, 201, &trap201); - set_interrupt_gate(0, 202, &trap202); - set_interrupt_gate(0, 203, &trap203); - set_interrupt_gate(0, 204, &trap204); - set_interrupt_gate(0, 205, &trap205); - set_interrupt_gate(0, 206, &trap206); - set_interrupt_gate(0, 207, &trap207); - set_interrupt_gate(0, 208, &trap208); - set_interrupt_gate(0, 209, &trap209); - set_interrupt_gate(0, 210, &trap210); - set_interrupt_gate(0, 211, &trap211); - set_interrupt_gate(0, 212, &trap212); - set_interrupt_gate(0, 213, &trap213); - set_interrupt_gate(0, 214, &trap214); - set_interrupt_gate(0, 215, &trap215); - set_interrupt_gate(0, 216, &trap216); - set_interrupt_gate(0, 217, &trap217); - set_interrupt_gate(0, 218, &trap218); - set_interrupt_gate(0, 219, &trap219); - set_interrupt_gate(0, 220, &trap220); - set_interrupt_gate(0, 221, &trap221); - set_interrupt_gate(0, 222, &trap222); - set_interrupt_gate(0, 223, &trap223); - set_interrupt_gate(0, 224, &trap224); - set_interrupt_gate(0, 225, &trap225); - set_interrupt_gate(0, 226, &trap226); - set_interrupt_gate(0, 227, &trap227); - set_interrupt_gate(0, 228, &trap228); - set_interrupt_gate(0, 229, &trap229); - set_interrupt_gate(0, 230, &trap230); - set_interrupt_gate(0, 231, &trap231); - set_interrupt_gate(0, 232, &trap232); - set_interrupt_gate(0, 233, &trap233); - set_interrupt_gate(0, 234, &trap234); - set_interrupt_gate(0, 235, &trap235); - set_interrupt_gate(0, 236, &trap236); - set_interrupt_gate(0, 237, &trap237); - set_interrupt_gate(0, 238, &trap238); - set_interrupt_gate(0, 239, &trap239); - set_interrupt_gate(0, 240, &trap240); - set_interrupt_gate(0, 241, &trap241); - set_interrupt_gate(0, 242, &trap242); - set_interrupt_gate(0, 243, &trap243); - set_interrupt_gate(0, 244, &trap244); - set_interrupt_gate(0, 245, &trap245); - set_interrupt_gate(0, 246, &trap246); - set_interrupt_gate(0, 247, &trap247); - set_interrupt_gate(0, 248, &trap248); - set_interrupt_gate(0, 249, &trap249); - set_interrupt_gate(0, 250, &trap250); - - // smp / apic local interrupts - set_interrupt_gate(0, 251, &trap251); - set_interrupt_gate(0, 252, &trap252); - set_interrupt_gate(0, 253, &trap253); - set_interrupt_gate(0, 254, &trap254); - set_interrupt_gate(0, 255, &trap255); + reserve_io_interrupt_vectors(2, 98, INTERRUPT_TYPE_SYSCALL); // init interrupt handler table - table = gInterruptHandlerTable; + interrupt_handler_function** table = gInterruptHandlerTable; // defaults + uint32 i; for (i = 0; i < ARCH_INTERRUPT_BASE; i++) table[i] = x86_invalid_exception; for (i = ARCH_INTERRUPT_BASE; i < kInterruptHandlerTableSize; i++) @@ -505,90 +595,14 @@ x86_descriptors_init(kernel_args* args) void -x86_descriptors_init_percpu(kernel_args* args, int cpu) +x86_descriptors_init_percpu(kernel_args* /* args */, int /* cpu */) { - // load the TSS for this cpu - // note the main cpu gets initialized in x86_descriptors_init_post_vm() - if (cpu != 0) { - load_tss(cpu); - - // set the IDT - struct { - uint16 limit; - void* address; - } _PACKED descriptor = { - 256 * 8 - 1, // 256 descriptors, 8 bytes each (-1 for "limit") - sIDTs[cpu] - }; - - asm volatile("lidt %0" : : "m"(descriptor)); - } } status_t -x86_descriptors_init_post_vm(kernel_args* args) +x86_descriptors_init_post_vm(kernel_args* /* args */) { - uint32 i; - - // account for the segment descriptors - create_area("gdt", (void **)&gGDT, B_EXACT_ADDRESS, B_PAGE_SIZE, - B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA); - - // create IDT area for the boot CPU - area_id area = create_area("idt", (void**)&sIDTs[0], B_EXACT_ADDRESS, - B_PAGE_SIZE, B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA); - if (area < B_OK) - return area; - - // create IDTs for the off-boot CPU - size_t idtSize = 256 * 8; - // 256 8 bytes-sized descriptors - if (args->num_cpus > 0) { - size_t areaSize = ROUNDUP(args->num_cpus * idtSize, B_PAGE_SIZE); - interrupt_descriptor* idt; - virtual_address_restrictions virtualRestrictions = {}; - virtualRestrictions.address_specification = B_ANY_KERNEL_ADDRESS; - physical_address_restrictions physicalRestrictions = {}; - area = create_area_etc(B_SYSTEM_TEAM, "idt", areaSize, B_CONTIGUOUS, - B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, CREATE_AREA_DONT_WAIT, - 0, &virtualRestrictions, &physicalRestrictions, (void**)&idt); - if (area < 0) - return area; - - for (i = 1; i < args->num_cpus; i++) { - sIDTs[i] = idt; - memcpy(idt, sIDTs[0], idtSize); - idt += 256; - // The CPU's IDTR will be set in arch_cpu_init_percpu(). - } - } - - // setup task-state segments - for (i = 0; i < args->num_cpus; i++) { - // initialize the regular and double fault tss stored in the per-cpu - // structure - memset(&gCPU[i].arch.tss, 0, sizeof(struct tss)); - gCPU[i].arch.tss.ss0 = KERNEL_DATA_SEG; - gCPU[i].arch.tss.io_map_base = sizeof(struct tss); - - // add TSS descriptor for this new TSS - set_tss_descriptor(&gGDT[TSS_SEGMENT(i)], (addr_t)&gCPU[i].arch.tss, - sizeof(struct tss)); - - // initialize the double fault tss - init_double_fault(i); - } - - // set the current hardware task on cpu 0 - load_tss(0); - - // setup TLS descriptors (one for every CPU) - - for (i = 0; i < args->num_cpus; i++) { - set_segment_descriptor(&gGDT[TLS_BASE_SEGMENT + i], 0, TLS_SIZE, - DT_DATA_WRITEABLE, DPL_USER); - } - return B_OK; } + diff --git a/src/system/kernel/arch/x86/32/interrupts.S b/src/system/kernel/arch/x86/32/interrupts.S index 912c583cb9..d42f66ed34 100644 --- a/src/system/kernel/arch/x86/32/interrupts.S +++ b/src/system/kernel/arch/x86/32/interrupts.S @@ -159,7 +159,7 @@ \ /* restore pointers and clear fault handler */ \ movl %edx, %esi; /* syscall info pointer */ \ - movl %dr3, %edi; /* thread pointer */ \ + movl %gs:0, %edi; /* thread pointer */ \ movl $0, THREAD_fault_handler(%edi) #if SYSCALL_TRACING @@ -223,7 +223,7 @@ FUNCTION(double_fault): pushl $-1; // user-ss pushl $-1; // user-esp pushl $-1; // flags - pushl $KERNEL_CODE_SEG; // cs + pushl $KERNEL_CODE_SELECTOR // cs pushl $-1; // eip pushl $0; // error-code pushl $8; @@ -509,6 +509,9 @@ FUNCTION_END(trap14_double_fault) STATIC_FUNCTION(int_bottom): PUSH_IFRAME_BOTTOM(IFRAME_TYPE_OTHER) + movl $KERNEL_TLS_SELECTOR, %edx + movw %dx, %gs + movl %esp, %ebp // frame pointer is the iframe // Set the RF (resume flag) in EFLAGS. This prevents an instruction @@ -516,7 +519,7 @@ STATIC_FUNCTION(int_bottom): // exception. orl $0x10000, IFRAME_flags(%ebp); - cmp $USER_CODE_SEG, IFRAME_cs(%ebp) // user mode + cmpw $USER_CODE_SELECTOR, IFRAME_cs(%ebp) // user mode je int_bottom_user // We need to recheck user mode using the thread's in_kernel flag, since @@ -524,7 +527,7 @@ STATIC_FUNCTION(int_bottom): // so that we have to do it in the instruction before, thus opening a // window for an interrupt while still being in the kernel, but having set // up everything for userland already. - movl %dr3, %edi // thread pointer + movl %gs:0, %edi // thread pointer cmpb $0, THREAD_in_kernel(%edi) je int_bottom_user @@ -540,13 +543,13 @@ FUNCTION_END(int_bottom) STATIC_FUNCTION(int_bottom_user): - movl $KERNEL_DATA_SEG,%eax + movl $KERNEL_DATA_SELECTOR, %eax cld movl %eax,%ds movl %eax,%es // disable breakpoints, if installed - movl %dr3, %edi // thread pointer + movl %gs:0, %edi // thread pointer cli // disable interrupts STOP_USER_DEBUGGING() @@ -564,7 +567,7 @@ STATIC_FUNCTION(int_bottom_user): // were already/still prepared for userland), since the iframe in this case // will be a kernel iframe and e.g. trying to set up a signal stack will not // be a very healthy endeavor. - cmp $USER_CODE_SEG, IFRAME_cs(%ebp) + cmpw $USER_CODE_SELECTOR, IFRAME_cs(%ebp) jne 1f testl $(THREAD_FLAGS_DEBUGGER_INSTALLED | THREAD_FLAGS_SIGNALS_PENDING \ @@ -600,17 +603,20 @@ FUNCTION_END(trap99) STATIC_FUNCTION(handle_syscall): + movl $KERNEL_TLS_SELECTOR, %edx + movw %dx, %gs + // save %eax, the number of the syscall movl %eax, %esi - movl $KERNEL_DATA_SEG,%eax + movl $KERNEL_DATA_SELECTOR, %eax cld movl %eax,%ds movl %eax,%es lea 4(%esp), %ebp // skipping the return address, the stack // frame pointer is the iframe - movl %dr3, %edi // thread pointer + movl %gs:0, %edi // thread pointer // disable breakpoints, if installed cli // disable interrupts @@ -745,7 +751,7 @@ FUNCTION_END(handle_syscall) STATIC_FUNCTION(bad_syscall_params): // clear the fault handler and exit normally - movl %dr3, %edi + movl %gs:0, %edi movl $0, THREAD_fault_handler(%edi) jmp kernel_exit_work FUNCTION_END(bad_syscall_params) @@ -756,14 +762,18 @@ FUNCTION_END(handle_syscall) */ FUNCTION(x86_sysenter): // get the thread - movl %dr3, %edx + push %gs + movl $KERNEL_TLS_SELECTOR, %edx + movw %dx, %gs + movl %gs:0, %edx + pop %gs // push the iframe - pushl $USER_DATA_SEG // user_ss + pushl $USER_DATA_SELECTOR // user_ss pushl %ecx // user_esp pushfl // eflags orl $(1 << 9), (%esp) // set the IF (interrupts) bit - pushl $USER_CODE_SEG // user cs + pushl $USER_CODE_SELECTOR // user cs // user_eip movl THREAD_team(%edx), %edx @@ -816,7 +826,7 @@ FUNCTION(x86_return_to_userland): movl %ebp, %esp // check, if any kernel exit work has to be done - movl %dr3, %edi + movl %gs:0, %edi testl $(THREAD_FLAGS_DEBUGGER_INSTALLED | THREAD_FLAGS_SIGNALS_PENDING \ | THREAD_FLAGS_DEBUG_THREAD | THREAD_FLAGS_BREAKPOINTS_DEFINED) \ , THREAD_flags(%edi) diff --git a/src/system/kernel/arch/x86/32/syscalls.cpp b/src/system/kernel/arch/x86/32/syscalls.cpp index 5b007e61e1..c3ca4e1a24 100644 --- a/src/system/kernel/arch/x86/32/syscalls.cpp +++ b/src/system/kernel/arch/x86/32/syscalls.cpp @@ -55,7 +55,7 @@ set_intel_syscall_stack(addr_t stackTop) static void init_intel_syscall_registers(void* dummy, int cpuNum) { - x86_write_msr(IA32_MSR_SYSENTER_CS, KERNEL_CODE_SEG); + x86_write_msr(IA32_MSR_SYSENTER_CS, KERNEL_CODE_SELECTOR); x86_write_msr(IA32_MSR_SYSENTER_ESP, 0); x86_write_msr(IA32_MSR_SYSENTER_EIP, (addr_t)x86_sysenter); diff --git a/src/system/kernel/arch/x86/32/thread.cpp b/src/system/kernel/arch/x86/32/thread.cpp index 7bed6a0f4d..a62575590b 100644 --- a/src/system/kernel/arch/x86/32/thread.cpp +++ b/src/system/kernel/arch/x86/32/thread.cpp @@ -69,7 +69,6 @@ class RestartSyscall : public AbstractTraceEntry { // from arch_cpu.cpp extern bool gHasSSE; -extern segment_descriptor* gGDT; static struct arch_thread sInitialState _ALIGNED(16); // the fpu_state must be aligned on a 16 byte boundary, so that fxsave can use it @@ -103,10 +102,10 @@ x86_restart_syscall(struct iframe* frame) void x86_set_tls_context(Thread *thread) { - int entry = smp_get_current_cpu() + TLS_BASE_SEGMENT; - - set_segment_descriptor_base(&gGDT[entry], thread->user_local_storage); - set_fs_register((entry << 3) | DPL_USER); + segment_descriptor* gdt = get_gdt(smp_get_current_cpu()); + set_segment_descriptor_base(&gdt[USER_TLS_SEGMENT], + thread->user_local_storage); + set_fs_register((USER_TLS_SEGMENT << 3) | DPL_USER); } @@ -197,7 +196,7 @@ arch_thread_init_kthread_stack(Thread* thread, void* _stack, void* _stackTop, // save the stack position thread->arch_info.current_stack.esp = stackTop; - thread->arch_info.current_stack.ss = (addr_t*)KERNEL_DATA_SEG; + thread->arch_info.current_stack.ss = (addr_t*)KERNEL_DATA_SELECTOR; } @@ -242,16 +241,16 @@ arch_thread_enter_userspace(Thread* thread, addr_t entry, void* args1, // prepare the user iframe iframe frame = {}; frame.type = IFRAME_TYPE_SYSCALL; - frame.gs = USER_DATA_SEG; + frame.gs = USER_DATA_SELECTOR; // frame.fs not used, we call x86_set_tls_context() on context switch - frame.es = USER_DATA_SEG; - frame.ds = USER_DATA_SEG; + frame.es = USER_DATA_SELECTOR; + frame.ds = USER_DATA_SELECTOR; frame.ip = entry; - frame.cs = USER_CODE_SEG; + frame.cs = USER_CODE_SELECTOR; frame.flags = X86_EFLAGS_RESERVED1 | X86_EFLAGS_INTERRUPT | (3 << X86_EFLAGS_IO_PRIVILEG_LEVEL_SHIFT); frame.user_sp = stackTop; - frame.user_ss = USER_DATA_SEG; + frame.user_ss = USER_DATA_SELECTOR; // return to userland x86_initial_return_to_userland(thread, &frame); diff --git a/src/system/kernel/arch/x86/64/cpuid.S b/src/system/kernel/arch/x86/64/cpuid.S index 8e6b07cd6b..1085359a1f 100644 --- a/src/system/kernel/arch/x86/64/cpuid.S +++ b/src/system/kernel/arch/x86/64/cpuid.S @@ -10,10 +10,12 @@ .text -/* status_t get_current_cpuid(cpuid_info* info, uint32 eaxRegister) */ +/* status_t get_current_cpuid(cpuid_info* info, uint32 eaxRegister, + uint32 ecxRegister) */ FUNCTION(get_current_cpuid): push %rbx movl %esi, %eax + movl %edx, %ecx cpuid movl %eax, 0(%rdi) movl %ebx, 4(%rdi) diff --git a/src/system/kernel/arch/x86/64/descriptors.cpp b/src/system/kernel/arch/x86/64/descriptors.cpp index 955f96c1e4..3e6878eb64 100644 --- a/src/system/kernel/arch/x86/64/descriptors.cpp +++ b/src/system/kernel/arch/x86/64/descriptors.cpp @@ -60,6 +60,12 @@ x86_64_general_protection_fault(iframe* frame) // #pragma mark - +void +x86_descriptors_preboot_init_percpu(kernel_args* /* args */, int /* cpu */) +{ +} + + void x86_descriptors_init(kernel_args* args) { @@ -83,7 +89,7 @@ x86_descriptors_init(kernel_args* args) uint32 dpl = (i == 3) ? DPL_USER : DPL_KERNEL; set_interrupt_descriptor(&sIDT[i], (addr_t)&isr_array[i], - GATE_INTERRUPT, KERNEL_CODE_SEG, dpl, ist); + GATE_INTERRUPT, KERNEL_CODE_SELECTOR, dpl, ist); } // Initialize the interrupt handler table. diff --git a/src/system/kernel/arch/x86/64/interrupts.S b/src/system/kernel/arch/x86/64/interrupts.S index 71a0d106db..db73a4fba4 100644 --- a/src/system/kernel/arch/x86/64/interrupts.S +++ b/src/system/kernel/arch/x86/64/interrupts.S @@ -302,10 +302,10 @@ FUNCTION(x86_64_syscall_entry): movq %gs:ARCH_THREAD_syscall_rsp, %rsp // Set up an iframe on the stack (R11 = saved RFLAGS, RCX = saved RIP). - push $USER_DATA_SEG // ss + push $USER_DATA_SELECTOR // ss push %gs:ARCH_THREAD_user_rsp // rsp push %r11 // flags - push $USER_CODE_SEG // cs + push $USER_CODE_SELECTOR // cs push %rcx // ip push $0 // error_code push $99 // vector diff --git a/src/system/kernel/arch/x86/64/syscalls.cpp b/src/system/kernel/arch/x86/64/syscalls.cpp index 4407498aa2..174755f5a0 100644 --- a/src/system/kernel/arch/x86/64/syscalls.cpp +++ b/src/system/kernel/arch/x86/64/syscalls.cpp @@ -38,12 +38,12 @@ init_syscall_registers(void* dummy, int cpuNum) // - CS is set to IA32_STAR[63:48] + 16 // - SS is set to IA32_STAR[63:48] + 8 // From this we get: - // - Entry CS = KERNEL_CODE_SEG - // - Entry SS = KERNEL_CODE_SEG + 8 = KERNEL_DATA_SEG - // - Return CS = KERNEL_DATA_SEG + 16 = USER_CODE_SEG - // - Return SS = KERNEL_DATA_SEG + 8 = USER_DATA_SEG - x86_write_msr(IA32_MSR_STAR, ((uint64)(KERNEL_DATA_SEG | 3) << 48) - | ((uint64)KERNEL_CODE_SEG << 32)); + // - Entry CS = KERNEL_CODE_SELECTOR + // - Entry SS = KERNEL_CODE_SELECTOR + 8 = KERNEL_DATA_SELECTOR + // - Return CS = KERNEL_DATA_SELECTOR + 16 = USER_CODE_SELECTOR + // - Return SS = KERNEL_DATA_SELECTOR + 8 = USER_DATA_SLECTORG + x86_write_msr(IA32_MSR_STAR, ((uint64)(KERNEL_DATA_SELECTOR | 3) << 48) + | ((uint64)KERNEL_CODE_SELECTOR << 32)); } diff --git a/src/system/kernel/arch/x86/64/thread.cpp b/src/system/kernel/arch/x86/64/thread.cpp index 59db5028e4..5ee839a711 100644 --- a/src/system/kernel/arch/x86/64/thread.cpp +++ b/src/system/kernel/arch/x86/64/thread.cpp @@ -238,11 +238,11 @@ arch_thread_enter_userspace(Thread* thread, addr_t entry, void* args1, frame.si = (uint64)args2; frame.di = (uint64)args1; frame.ip = entry; - frame.cs = USER_CODE_SEG; + frame.cs = USER_CODE_SELECTOR; frame.flags = X86_EFLAGS_RESERVED1 | X86_EFLAGS_INTERRUPT | (3 << X86_EFLAGS_IO_PRIVILEG_LEVEL_SHIFT); frame.sp = stackTop; - frame.ss = USER_DATA_SEG; + frame.ss = USER_DATA_SELECTOR; // Return to userland. Never returns. x86_initial_return_to_userland(thread, &frame); diff --git a/src/system/kernel/arch/x86/apic.cpp b/src/system/kernel/arch/x86/apic.cpp index 47587063a3..176102977d 100644 --- a/src/system/kernel/arch/x86/apic.cpp +++ b/src/system/kernel/arch/x86/apic.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include "timers/apic_timer.h" @@ -30,6 +31,13 @@ apic_available() } +bool +x2apic_available() +{ + return sX2APIC; +} + + uint32 apic_read(uint32 offset) { @@ -94,6 +102,16 @@ apic_end_of_interrupt() } +uint32 +apic_logical_apic_id() +{ + if (sX2APIC) + return x86_read_msr(IA32_MSR_APIC_LOGICAL_DEST); + else + return apic_read(APIC_LOGICAL_DEST); +} + + void apic_disable_local_ints() { @@ -128,49 +146,36 @@ apic_set_spurious_intr_vector(uint32 config) } -uint32 -apic_intr_command_1() -{ - if (sX2APIC) - return x86_read_msr(IA32_MSR_APIC_INTR_COMMAND) & 0xffffffff; - else - return apic_read(APIC_INTR_COMMAND_1); -} - - void -apic_set_intr_command_1(uint32 config) +apic_set_interrupt_command(uint32 destination, uint32 mode) { if (sX2APIC) { - uint64 value = x86_read_msr(IA32_MSR_APIC_INTR_COMMAND); - arch_cpu_memory_read_write_barrier(); - x86_write_msr(IA32_MSR_APIC_INTR_COMMAND, - (value & 0xffffffff00000000LL) | config); - } else - apic_write(APIC_INTR_COMMAND_1, config); + uint64 command = x86_read_msr(IA32_MSR_APIC_INTR_COMMAND); + command &= APIC_INTR_COMMAND_1_MASK; + command |= (uint64)destination << 32; + command |= mode; + x86_write_msr(IA32_MSR_APIC_INTR_COMMAND, command); + } else { + uint32 command2 = apic_read(APIC_INTR_COMMAND_2) + & APIC_INTR_COMMAND_2_MASK; + command2 |= destination << 24; + apic_write(APIC_INTR_COMMAND_2, command2); + + uint32 command1 = apic_read(APIC_INTR_COMMAND_1) + & APIC_INTR_COMMAND_1_MASK; + command1 |= mode; + apic_write(APIC_INTR_COMMAND_1, command1); + } } -uint32 -apic_intr_command_2() +bool +apic_interrupt_delivered(void) { if (sX2APIC) - return x86_read_msr(IA32_MSR_APIC_INTR_COMMAND) >> 32; + return true; else - return apic_read(APIC_INTR_COMMAND_2); -} - - -void -apic_set_intr_command_2(uint32 config) -{ - if (sX2APIC) { - uint64 value = x86_read_msr(IA32_MSR_APIC_INTR_COMMAND); - arch_cpu_memory_read_write_barrier(); - x86_write_msr(IA32_MSR_APIC_INTR_COMMAND, - (value & 0xffffffff) | ((uint64)config << 32)); - } else - apic_write(APIC_INTR_COMMAND_2, config); + return (apic_read(APIC_INTR_COMMAND_1) & APIC_DELIVERY_STATUS) == 0; } @@ -264,11 +269,6 @@ apic_init(kernel_args *args) dprintf("found x2apic\n"); #if 0 if (!get_safemode_boolean(B_SAFEMODE_DISABLE_X2APIC, false)) { - uint64 apic_base = x86_read_msr(IA32_MSR_APIC_BASE); - if ((apic_base & IA32_MSR_APIC_BASE_X2APIC) == 0) { - x86_write_msr(IA32_MSR_APIC_BASE, apic_base - | IA32_MSR_APIC_BASE_X2APIC); - } sX2APIC = true; return B_OK; } @@ -276,11 +276,6 @@ apic_init(kernel_args *args) dprintf("x2apic disabled per safemode setting\n"); #else if (get_safemode_boolean(B_SAFEMODE_ENABLE_X2APIC, false)) { - uint64 apic_base = x86_read_msr(IA32_MSR_APIC_BASE); - if ((apic_base & IA32_MSR_APIC_BASE_X2APIC) == 0) { - x86_write_msr(IA32_MSR_APIC_BASE, apic_base - | IA32_MSR_APIC_BASE_X2APIC); - } sX2APIC = true; dprintf("x2apic enabled per safemode setting\n"); @@ -306,8 +301,33 @@ apic_init(kernel_args *args) status_t apic_per_cpu_init(kernel_args *args, int32 cpu) { - dprintf("setting up apic for CPU %" B_PRId32 ": apic id %" B_PRIu32 ", " - "version %" B_PRIu32 "\n", cpu, apic_local_id(), apic_version()); + if (sX2APIC) { + uint64 apic_base = x86_read_msr(IA32_MSR_APIC_BASE); + if ((apic_base & IA32_MSR_APIC_BASE_X2APIC) == 0) { + x86_write_msr(IA32_MSR_APIC_BASE, apic_base + | IA32_MSR_APIC_BASE_X2APIC); + } + } + + dprintf("setting up %sapic for CPU %" B_PRId32 ": apic id %" B_PRIu32 ", " + "version %" B_PRIu32 "\n", sX2APIC ? "x2" : "", cpu, apic_local_id(), + apic_version()); + + if (!sX2APIC && cpu < 8) { + apic_write(APIC_DEST_FORMAT, uint32(-1)); + + uint8 logical_apic_id = 1 << cpu; + uint32 value = apic_read(APIC_LOGICAL_DEST); + value &= 0xffffff; + apic_write(APIC_LOGICAL_DEST, value | (logical_apic_id << 24)); + } + + // get logical APIC ID + gCPU[cpu].arch.logical_apic_id = apic_logical_apic_id(); + if (!sX2APIC) + gCPU[cpu].arch.logical_apic_id >>= 24; + dprintf("CPU %" B_PRId32 ": logical apic id: %#" B_PRIx32 "\n", cpu, + gCPU[cpu].arch.logical_apic_id); /* set spurious interrupt vector to 0xff */ uint32 config = apic_spurious_intr_vector() & 0xffffff00; diff --git a/src/system/kernel/arch/x86/arch_cpu.cpp b/src/system/kernel/arch/x86/arch_cpu.cpp index a817ec05b7..a21afcde52 100644 --- a/src/system/kernel/arch/x86/arch_cpu.cpp +++ b/src/system/kernel/arch/x86/arch_cpu.cpp @@ -1,5 +1,6 @@ /* * Copyright 2002-2010, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2013, Paweł Dziepak, pdziepak@quarnos.org. * Copyright 2012, Alex Smith, alex@alex-smith.me.uk. * Distributed under the terms of the MIT License. * @@ -14,6 +15,8 @@ #include #include +#include + #include #include @@ -21,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -34,6 +38,7 @@ #define DUMP_FEATURE_STRING 1 +#define DUMP_CPU_TOPOLOGY 1 /* cpu vendor info */ @@ -67,16 +72,6 @@ static const struct cpu_vendor_info vendor_info[VENDOR_NUM] = { #define K8_CMPHALT (K8_SMIONCMPHALT | K8_C1EONCMPHALT) -/* - * 0 favors highest performance while 15 corresponds to the maximum energy - * savings. 7 means balance between performance and energy savings. - * Refer to Section 14.3.4 in for details - */ -#define ENERGY_PERF_BIAS_PERFORMANCE 0 -#define ENERGY_PERF_BIAS_BALANCE 7 -#define ENERGY_PERF_BIAS_POWERSAVE 15 - struct set_mtrr_parameter { int32 index; uint64 base; @@ -122,6 +117,14 @@ x86_optimized_functions gOptimizedFunctions = { &memset_generic_end }; +/* CPU topology information */ +static uint32 (*sGetCPUTopologyID)(int currentCPU); +static uint32 sHierarchyMask[CPU_TOPOLOGY_LEVELS]; +static uint32 sHierarchyShift[CPU_TOPOLOGY_LEVELS]; + +/* Cache topology information */ +static uint32 sCacheSharingMask[CPU_MAX_CACHE_LEVEL]; + static status_t acpi_shutdown(bool rebootSystem) @@ -144,7 +147,7 @@ acpi_shutdown(bool rebootSystem) _user_set_cpu_enabled(cpu, false); } // TODO: must not be called from the idle thread! - thread_yield(true); + thread_yield(); status = acpi->prepare_sleep_state(ACPI_POWER_STATE_OFF, NULL, 0); if (status == B_OK) { @@ -188,14 +191,14 @@ set_mtrr(void* _parameter, int cpu) = (struct set_mtrr_parameter*)_parameter; // wait until all CPUs have arrived here - smp_cpu_rendezvous(&sCpuRendezvous, cpu); + smp_cpu_rendezvous(&sCpuRendezvous); // One CPU has to reset sCpuRendezvous3 -- it is needed to prevent the CPU // that initiated the call_all_cpus() from doing that again and clearing // sCpuRendezvous2 before the last CPU has actually left the loop in // smp_cpu_rendezvous(); if (cpu == 0) - atomic_set((vint32*)&sCpuRendezvous3, 0); + atomic_set((int32*)&sCpuRendezvous3, 0); disable_caches(); @@ -205,8 +208,8 @@ set_mtrr(void* _parameter, int cpu) enable_caches(); // wait until all CPUs have arrived here - smp_cpu_rendezvous(&sCpuRendezvous2, cpu); - smp_cpu_rendezvous(&sCpuRendezvous3, cpu); + smp_cpu_rendezvous(&sCpuRendezvous2); + smp_cpu_rendezvous(&sCpuRendezvous3); } @@ -216,14 +219,14 @@ set_mtrrs(void* _parameter, int cpu) set_mtrrs_parameter* parameter = (set_mtrrs_parameter*)_parameter; // wait until all CPUs have arrived here - smp_cpu_rendezvous(&sCpuRendezvous, cpu); + smp_cpu_rendezvous(&sCpuRendezvous); // One CPU has to reset sCpuRendezvous3 -- it is needed to prevent the CPU // that initiated the call_all_cpus() from doing that again and clearing // sCpuRendezvous2 before the last CPU has actually left the loop in // smp_cpu_rendezvous(); if (cpu == 0) - atomic_set((vint32*)&sCpuRendezvous3, 0); + atomic_set((int32*)&sCpuRendezvous3, 0); disable_caches(); @@ -233,8 +236,8 @@ set_mtrrs(void* _parameter, int cpu) enable_caches(); // wait until all CPUs have arrived here - smp_cpu_rendezvous(&sCpuRendezvous2, cpu); - smp_cpu_rendezvous(&sCpuRendezvous3, cpu); + smp_cpu_rendezvous(&sCpuRendezvous2); + smp_cpu_rendezvous(&sCpuRendezvous3); } @@ -242,14 +245,14 @@ static void init_mtrrs(void* _unused, int cpu) { // wait until all CPUs have arrived here - smp_cpu_rendezvous(&sCpuRendezvous, cpu); + smp_cpu_rendezvous(&sCpuRendezvous); // One CPU has to reset sCpuRendezvous3 -- it is needed to prevent the CPU // that initiated the call_all_cpus() from doing that again and clearing // sCpuRendezvous2 before the last CPU has actually left the loop in // smp_cpu_rendezvous(); if (cpu == 0) - atomic_set((vint32*)&sCpuRendezvous3, 0); + atomic_set((int32*)&sCpuRendezvous3, 0); disable_caches(); @@ -258,8 +261,8 @@ init_mtrrs(void* _unused, int cpu) enable_caches(); // wait until all CPUs have arrived here - smp_cpu_rendezvous(&sCpuRendezvous2, cpu); - smp_cpu_rendezvous(&sCpuRendezvous3, cpu); + smp_cpu_rendezvous(&sCpuRendezvous2); + smp_cpu_rendezvous(&sCpuRendezvous3); } @@ -506,6 +509,308 @@ dump_feature_string(int currentCPU, cpu_ent* cpu) #endif // DUMP_FEATURE_STRING +static void +compute_cpu_hierarchy_masks(int maxLogicalID, int maxCoreID) +{ + ASSERT(maxLogicalID >= maxCoreID); + const int kMaxSMTID = maxLogicalID / maxCoreID; + + sHierarchyMask[CPU_TOPOLOGY_SMT] = kMaxSMTID - 1; + sHierarchyShift[CPU_TOPOLOGY_SMT] = 0; + + sHierarchyMask[CPU_TOPOLOGY_CORE] = (maxCoreID - 1) * kMaxSMTID; + sHierarchyShift[CPU_TOPOLOGY_CORE] + = count_set_bits(sHierarchyMask[CPU_TOPOLOGY_SMT]); + + const uint32 kSinglePackageMask = sHierarchyMask[CPU_TOPOLOGY_SMT] + | sHierarchyMask[CPU_TOPOLOGY_CORE]; + sHierarchyMask[CPU_TOPOLOGY_PACKAGE] = ~kSinglePackageMask; + sHierarchyShift[CPU_TOPOLOGY_PACKAGE] = count_set_bits(kSinglePackageMask); +} + + +static uint32 +get_cpu_legacy_initial_apic_id(int /* currentCPU */) +{ + cpuid_info cpuid; + get_current_cpuid(&cpuid, 1, 0); + return cpuid.regs.ebx >> 24; +} + + +static inline status_t +detect_amd_cpu_topology(uint32 maxBasicLeaf, uint32 maxExtendedLeaf) +{ + sGetCPUTopologyID = get_cpu_legacy_initial_apic_id; + + cpuid_info cpuid; + get_current_cpuid(&cpuid, 1, 0); + int maxLogicalID = next_power_of_2((cpuid.regs.ebx >> 16) & 0xff); + + int maxCoreID = 1; + if (maxExtendedLeaf >= 0x80000008) { + get_current_cpuid(&cpuid, 0x80000008, 0); + maxCoreID = (cpuid.regs.ecx >> 12) & 0xf; + if (maxCoreID != 0) + maxCoreID = 1 << maxCoreID; + else + maxCoreID = next_power_of_2((cpuid.regs.edx & 0xf) + 1); + } + + if (maxExtendedLeaf >= 0x80000001) { + get_current_cpuid(&cpuid, 0x80000001, 0); + if (x86_check_feature(IA32_FEATURE_AMD_EXT_CMPLEGACY, + FEATURE_EXT_AMD_ECX)) + maxCoreID = maxLogicalID; + } + + compute_cpu_hierarchy_masks(maxLogicalID, maxCoreID); + + return B_OK; +} + + +static void +detect_amd_cache_topology(uint32 maxExtendedLeaf) +{ + if (!x86_check_feature(IA32_FEATURE_AMD_EXT_TOPOLOGY, FEATURE_EXT_AMD_ECX)) + return; + + if (maxExtendedLeaf < 0x8000001d) + return; + + uint8 hierarchyLevels[CPU_MAX_CACHE_LEVEL]; + int maxCacheLevel = 0; + + int currentLevel = 0; + int cacheType; + do { + cpuid_info cpuid; + get_current_cpuid(&cpuid, 0x8000001d, currentLevel); + + cacheType = cpuid.regs.eax & 0x1f; + if (cacheType == 0) + break; + + int cacheLevel = (cpuid.regs.eax >> 5) & 0x7; + int coresCount = next_power_of_2(((cpuid.regs.eax >> 14) & 0x3f) + 1); + hierarchyLevels[cacheLevel - 1] + = coresCount * (sHierarchyMask[CPU_TOPOLOGY_SMT] + 1); + maxCacheLevel = std::max(maxCacheLevel, cacheLevel); + + currentLevel++; + } while (true); + + for (int i = 0; i < maxCacheLevel; i++) + sCacheSharingMask[i] = ~uint32(hierarchyLevels[i] - 1); + gCPUCacheLevelCount = maxCacheLevel; +} + + +static uint32 +get_intel_cpu_initial_x2apic_id(int /* currentCPU */) +{ + cpuid_info cpuid; + get_current_cpuid(&cpuid, 11, 0); + return cpuid.regs.edx; +} + + +static inline status_t +detect_intel_cpu_topology_x2apic(uint32 maxBasicLeaf) +{ + if (maxBasicLeaf < 11) + return B_UNSUPPORTED; + + uint8 hierarchyLevels[CPU_TOPOLOGY_LEVELS]; + + int currentLevel = 0; + int levelType; + int levelsSet = 0; + + do { + cpuid_info cpuid; + get_current_cpuid(&cpuid, 11, currentLevel); + if (currentLevel == 0 && cpuid.regs.ebx == 0) + return B_UNSUPPORTED; + + levelType = (cpuid.regs.ecx >> 8) & 0xff; + switch (levelType) { + case 1: // SMT + hierarchyLevels[CPU_TOPOLOGY_SMT] = cpuid.regs.eax & 0x1f; + levelsSet |= 1; + break; + case 2: // core + hierarchyLevels[CPU_TOPOLOGY_CORE] = cpuid.regs.eax & 0x1f; + levelsSet |= 2; + break; + } + + currentLevel++; + } while (levelType != 0 && levelsSet != 3); + + sGetCPUTopologyID = get_intel_cpu_initial_x2apic_id; + + for (int i = 0; i < CPU_TOPOLOGY_LEVELS; i++) { + uint32 mask = ~uint32(0); + if (i < CPU_TOPOLOGY_LEVELS - 1) + mask = (1 << hierarchyLevels[i]) - 1; + if (i > 0) + mask &= ~sHierarchyMask[i - 1]; + sHierarchyMask[i] = mask; + sHierarchyShift[i] = i > 0 ? hierarchyLevels[i - 1] : 0; + } + + return B_OK; +} + + +static inline status_t +detect_intel_cpu_topology_legacy(uint32 maxBasicLeaf) +{ + sGetCPUTopologyID = get_cpu_legacy_initial_apic_id; + + cpuid_info cpuid; + + get_current_cpuid(&cpuid, 1, 0); + int maxLogicalID = next_power_of_2((cpuid.regs.ebx >> 16) & 0xff); + + int maxCoreID = 1; + if (maxBasicLeaf >= 4) { + get_current_cpuid(&cpuid, 4, 0); + maxCoreID = next_power_of_2((cpuid.regs.eax >> 26) + 1); + } + + compute_cpu_hierarchy_masks(maxLogicalID, maxCoreID); + + return B_OK; +} + + +static void +detect_intel_cache_topology(uint32 maxBasicLeaf) +{ + if (maxBasicLeaf < 4) + return; + + uint8 hierarchyLevels[CPU_MAX_CACHE_LEVEL]; + int maxCacheLevel = 0; + + int currentLevel = 0; + int cacheType; + do { + cpuid_info cpuid; + get_current_cpuid(&cpuid, 4, currentLevel); + + cacheType = cpuid.regs.eax & 0x1f; + if (cacheType == 0) + break; + + int cacheLevel = (cpuid.regs.eax >> 5) & 0x7; + hierarchyLevels[cacheLevel - 1] + = next_power_of_2(((cpuid.regs.eax >> 14) & 0x3f) + 1); + maxCacheLevel = std::max(maxCacheLevel, cacheLevel); + + currentLevel++; + } while (true); + + for (int i = 0; i < maxCacheLevel; i++) + sCacheSharingMask[i] = ~uint32(hierarchyLevels[i] - 1); + + gCPUCacheLevelCount = maxCacheLevel; +} + + +static uint32 +get_simple_cpu_topology_id(int currentCPU) +{ + return currentCPU; +} + + +static inline int +get_topology_level_id(uint32 id, cpu_topology_level level) +{ + ASSERT(level < CPU_TOPOLOGY_LEVELS); + return (id & sHierarchyMask[level]) >> sHierarchyShift[level]; +} + + +static void +detect_cpu_topology(int currentCPU, cpu_ent* cpu, uint32 maxBasicLeaf, + uint32 maxExtendedLeaf) +{ + if (currentCPU == 0) { + memset(sCacheSharingMask, 0xff, sizeof(sCacheSharingMask)); + + status_t result = B_UNSUPPORTED; + if (x86_check_feature(IA32_FEATURE_HTT, FEATURE_COMMON)) { + if (cpu->arch.vendor == VENDOR_AMD) { + result = detect_amd_cpu_topology(maxBasicLeaf, maxExtendedLeaf); + + if (result == B_OK) + detect_amd_cache_topology(maxExtendedLeaf); + } + + if (cpu->arch.vendor == VENDOR_INTEL) { + result = detect_intel_cpu_topology_x2apic(maxBasicLeaf); + if (result != B_OK) + result = detect_intel_cpu_topology_legacy(maxBasicLeaf); + + if (result == B_OK) + detect_intel_cache_topology(maxBasicLeaf); + } + } + + if (result != B_OK) { + dprintf("No CPU topology information available.\n"); + + sGetCPUTopologyID = get_simple_cpu_topology_id; + + sHierarchyMask[CPU_TOPOLOGY_PACKAGE] = ~uint32(0); + } + } + + ASSERT(sGetCPUTopologyID != NULL); + int topologyID = sGetCPUTopologyID(currentCPU); + cpu->topology_id[CPU_TOPOLOGY_SMT] + = get_topology_level_id(topologyID, CPU_TOPOLOGY_SMT); + cpu->topology_id[CPU_TOPOLOGY_CORE] + = get_topology_level_id(topologyID, CPU_TOPOLOGY_CORE); + cpu->topology_id[CPU_TOPOLOGY_PACKAGE] + = get_topology_level_id(topologyID, CPU_TOPOLOGY_PACKAGE); + + unsigned int i; + for (i = 0; i < gCPUCacheLevelCount; i++) + cpu->cache_id[i] = topologyID & sCacheSharingMask[i]; + for (; i < CPU_MAX_CACHE_LEVEL; i++) + cpu->cache_id[i] = -1; + +#if DUMP_CPU_TOPOLOGY + dprintf("CPU %d: apic id %d, package %d, core %d, smt %d\n", currentCPU, + topologyID, cpu->topology_id[CPU_TOPOLOGY_PACKAGE], + cpu->topology_id[CPU_TOPOLOGY_CORE], + cpu->topology_id[CPU_TOPOLOGY_SMT]); + + if (gCPUCacheLevelCount > 0) { + char cacheLevels[256]; + unsigned int offset = 0; + for (i = 0; i < gCPUCacheLevelCount; i++) { + offset += snprintf(cacheLevels + offset, + sizeof(cacheLevels) - offset, + " L%d id %d%s", i + 1, cpu->cache_id[i], + i < gCPUCacheLevelCount - 1 ? "," : ""); + + if (offset >= sizeof(cacheLevels)) + break; + } + + dprintf("CPU %d: cache sharing:%s\n", currentCPU, cacheLevels); + } +#endif +} + + static void detect_cpu(int currentCPU) { @@ -522,7 +827,7 @@ detect_cpu(int currentCPU) cpu->arch.model_name[0] = 0; // print some fun data - get_current_cpuid(&cpuid, 0); + get_current_cpuid(&cpuid, 0, 0); uint32 maxBasicLeaf = cpuid.eax_0.max_eax; // build the vendor string @@ -530,7 +835,7 @@ detect_cpu(int currentCPU) memcpy(vendorString, cpuid.eax_0.vendor_id, sizeof(cpuid.eax_0.vendor_id)); // get the family, model, stepping - get_current_cpuid(&cpuid, 1); + get_current_cpuid(&cpuid, 1, 0); cpu->arch.type = cpuid.eax_1.type; cpu->arch.family = cpuid.eax_1.family; cpu->arch.extended_family = cpuid.eax_1.extended_family; @@ -561,27 +866,27 @@ detect_cpu(int currentCPU) } // see if we can get the model name - get_current_cpuid(&cpuid, 0x80000000); + get_current_cpuid(&cpuid, 0x80000000, 0); uint32 maxExtendedLeaf = cpuid.eax_0.max_eax; if (maxExtendedLeaf >= 0x80000004) { // build the model string (need to swap ecx/edx data before copying) unsigned int temp; memset(cpu->arch.model_name, 0, sizeof(cpu->arch.model_name)); - get_current_cpuid(&cpuid, 0x80000002); + get_current_cpuid(&cpuid, 0x80000002, 0); temp = cpuid.regs.edx; cpuid.regs.edx = cpuid.regs.ecx; cpuid.regs.ecx = temp; memcpy(cpu->arch.model_name, cpuid.as_chars, sizeof(cpuid.as_chars)); - get_current_cpuid(&cpuid, 0x80000003); + get_current_cpuid(&cpuid, 0x80000003, 0); temp = cpuid.regs.edx; cpuid.regs.edx = cpuid.regs.ecx; cpuid.regs.ecx = temp; memcpy(cpu->arch.model_name + 16, cpuid.as_chars, sizeof(cpuid.as_chars)); - get_current_cpuid(&cpuid, 0x80000004); + get_current_cpuid(&cpuid, 0x80000004, 0); temp = cpuid.regs.edx; cpuid.regs.edx = cpuid.regs.ecx; cpuid.regs.ecx = temp; @@ -604,23 +909,37 @@ detect_cpu(int currentCPU) } // load feature bits - get_current_cpuid(&cpuid, 1); + get_current_cpuid(&cpuid, 1, 0); cpu->arch.feature[FEATURE_COMMON] = cpuid.eax_1.features; // edx cpu->arch.feature[FEATURE_EXT] = cpuid.eax_1.extended_features; // ecx if (maxExtendedLeaf >= 0x80000001) { - get_current_cpuid(&cpuid, 0x80000001); + get_current_cpuid(&cpuid, 0x80000001, 0); + if (cpu->arch.vendor == VENDOR_AMD) + cpu->arch.feature[FEATURE_EXT_AMD_ECX] = cpuid.regs.ecx; // ecx cpu->arch.feature[FEATURE_EXT_AMD] = cpuid.regs.edx; // edx if (cpu->arch.vendor != VENDOR_AMD) cpu->arch.feature[FEATURE_EXT_AMD] &= IA32_FEATURES_INTEL_EXT; } + if (maxBasicLeaf >= 5) { + get_current_cpuid(&cpuid, 5, 0); + cpu->arch.feature[FEATURE_5_ECX] = cpuid.regs.ecx; + } + if (maxBasicLeaf >= 6) { - get_current_cpuid(&cpuid, 6); + get_current_cpuid(&cpuid, 6, 0); cpu->arch.feature[FEATURE_6_EAX] = cpuid.regs.eax; cpu->arch.feature[FEATURE_6_ECX] = cpuid.regs.ecx; } + if (maxExtendedLeaf >= 0x80000007) { + get_current_cpuid(&cpuid, 0x80000007, 0); + cpu->arch.feature[FEATURE_EXT_7_EDX] = cpuid.regs.edx; + } + + detect_cpu_topology(currentCPU, cpu, maxBasicLeaf, maxExtendedLeaf); + #if DUMP_FEATURE_STRING dump_feature_string(currentCPU, cpu); #endif @@ -691,6 +1010,8 @@ arch_cpu_preboot_init_percpu(kernel_args* args, int cpu) x86_write_msr(IA32_MSR_TSC, 0); } + x86_descriptors_preboot_init_percpu(args, cpu); + return B_OK; } @@ -732,7 +1053,6 @@ detect_amdc1e_noarat() status_t arch_cpu_init_percpu(kernel_args* args, int cpu) { - // Load descriptor tables for this CPU. x86_descriptors_init_percpu(args, cpu); detect_cpu(cpu); @@ -744,15 +1064,6 @@ arch_cpu_init_percpu(kernel_args* args, int cpu) gCpuIdleFunc = halt_idle; } - if (x86_check_feature(IA32_FEATURE_EPB, FEATURE_6_ECX)) { - uint64 msr = x86_read_msr(IA32_MSR_ENERGY_PERF_BIAS); - if ((msr & 0xf) == ENERGY_PERF_BIAS_PERFORMANCE) { - msr &= ~0xf; - msr |= ENERGY_PERF_BIAS_BALANCE; - x86_write_msr(IA32_MSR_ENERGY_PERF_BIAS, msr); - } - } - return B_OK; } @@ -971,51 +1282,9 @@ arch_cpu_shutdown(bool rebootSystem) } -void -arch_cpu_idle(void) -{ - gCpuIdleFunc(); -} - - void arch_cpu_sync_icache(void* address, size_t length) { // instruction cache is always consistent on x86 } - -void -arch_cpu_memory_read_barrier(void) -{ -#ifdef __x86_64__ - asm volatile("lfence" : : : "memory"); -#else - asm volatile ("lock;" : : : "memory"); - asm volatile ("addl $0, 0(%%esp);" : : : "memory"); -#endif -} - - -void -arch_cpu_memory_write_barrier(void) -{ -#ifdef __x86_64__ - asm volatile("sfence" : : : "memory"); -#else - asm volatile ("lock;" : : : "memory"); - asm volatile ("addl $0, 0(%%esp);" : : : "memory"); -#endif -} - - -void -arch_cpu_memory_read_write_barrier(void) -{ -#ifdef __x86_64__ - asm volatile("mfence" : : : "memory"); -#else - asm volatile ("lock;" : : : "memory"); - asm volatile ("addl $0, 0(%%esp);" : : : "memory"); -#endif -} diff --git a/src/system/kernel/arch/x86/arch_debug.cpp b/src/system/kernel/arch/x86/arch_debug.cpp index ea84e5c807..199f16f402 100644 --- a/src/system/kernel/arch/x86/arch_debug.cpp +++ b/src/system/kernel/arch/x86/arch_debug.cpp @@ -1202,13 +1202,13 @@ arch_debug_get_interrupt_pc(bool* _isSyscall) void arch_debug_unset_current_thread(void) { -#ifdef __x86_64__ // Can't just write 0 to the GS base, that will cause the read from %gs:0 // to fault. Instead point it at a NULL pointer, %gs:0 will get this value. static Thread* unsetThread = NULL; +#ifdef __x86_64__ x86_write_msr(IA32_MSR_GS_BASE, (addr_t)&unsetThread); #else - x86_write_dr3(NULL); + asm volatile("mov %0, %%gs:0" : : "r" (unsetThread) : "memory"); #endif } diff --git a/src/system/kernel/arch/x86/arch_debug_console.cpp b/src/system/kernel/arch/x86/arch_debug_console.cpp index 8309a9967b..1f226dbc56 100644 --- a/src/system/kernel/arch/x86/arch_debug_console.cpp +++ b/src/system/kernel/arch/x86/arch_debug_console.cpp @@ -316,7 +316,7 @@ arch_debug_blue_screen_getchar(void) if (c >= 0) return (char)c; - PAUSE(); + arch_cpu_pause(); } } @@ -352,7 +352,7 @@ arch_debug_serial_getchar(void) if ((lineStatus & 0x1) != 0) break; - PAUSE(); + arch_cpu_pause(); } return in8(sSerialBasePort + SERIAL_RECEIVE_BUFFER); diff --git a/src/system/kernel/arch/x86/arch_int.cpp b/src/system/kernel/arch/x86/arch_int.cpp index 1fabe85b1b..89b82575df 100644 --- a/src/system/kernel/arch/x86/arch_int.cpp +++ b/src/system/kernel/arch/x86/arch_int.cpp @@ -24,6 +24,7 @@ #include #include +#include #include #include @@ -41,6 +42,8 @@ #endif +static irq_source sVectorSources[NUM_IO_VECTORS]; + static const char *kInterruptNames[] = { /* 0 */ "Divide Error Exception", /* 1 */ "Debug Exception", @@ -231,8 +234,8 @@ x86_hardware_interrupt(struct iframe* frame) cpu_status state = disable_interrupts(); if (thread->cpu->invoke_scheduler) { - SpinLocker schedulerLocker(gSchedulerLock); - scheduler_reschedule(); + SpinLocker schedulerLocker(thread->scheduler_lock); + scheduler_reschedule(B_THREAD_READY); schedulerLocker.Unlock(); restore_interrupts(state); } else if (thread->post_interrupt_callback != NULL) { @@ -331,6 +334,13 @@ x86_page_fault_exception(struct iframe* frame) } +void +x86_set_irq_source(int irq, irq_source source) +{ + sVectorSources[irq] = source; +} + + // #pragma mark - @@ -389,6 +399,25 @@ arch_int_are_interrupts_enabled(void) } +void +arch_int_assign_to_cpu(int32 irq, int32 cpu) +{ + switch (sVectorSources[irq]) { + case IRQ_SOURCE_IOAPIC: + if (sCurrentPIC->assign_interrupt_to_cpu != NULL) + sCurrentPIC->assign_interrupt_to_cpu(irq, cpu); + break; + + case IRQ_SOURCE_MSI: + msi_assign_interrupt_to_cpu(irq, cpu); + break; + + default: + break; + } +} + + status_t arch_int_init(kernel_args* args) { diff --git a/src/system/kernel/arch/x86/arch_smp.cpp b/src/system/kernel/arch/x86/arch_smp.cpp index 8c2bc75326..fd5535157f 100644 --- a/src/system/kernel/arch/x86/arch_smp.cpp +++ b/src/system/kernel/arch/x86/arch_smp.cpp @@ -1,4 +1,5 @@ /* + * Copyright 2013, Paweł Dziepak, pdziepak@quarnos.org. * Copyright 2002-2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved. * Distributed under the terms of the MIT License. * @@ -9,10 +10,12 @@ #include #include +#include #include #include #include +#include #include #include #include @@ -25,6 +28,8 @@ #include #include +#include + //#define TRACE_ARCH_SMP #ifdef TRACE_ARCH_SMP @@ -34,8 +39,11 @@ #endif -static uint32 sCPUAPICIds[B_MAX_CPU_COUNT]; -static uint32 sAPICVersions[B_MAX_CPU_COUNT]; +#define ICI_VECTOR 0xfd + + +static uint32 sCPUAPICIds[SMP_MAX_CPUS]; +static uint32 sAPICVersions[SMP_MAX_CPUS]; static int32 @@ -70,6 +78,14 @@ x86_smp_error_interrupt(void *data) } +uint32 +x86_get_cpu_apic_id(int32 cpu) +{ + ASSERT(cpu >= 0 && cpu < SMP_MAX_CPUS); + return sCPUAPICIds[cpu]; +} + + status_t arch_smp_init(kernel_args *args) { @@ -90,7 +106,8 @@ arch_smp_init(kernel_args *args) if (args->num_cpus > 1) { // I/O interrupts start at ARCH_INTERRUPT_BASE, so all interrupts are shifted - reserve_io_interrupt_vectors(3, 0xfd - ARCH_INTERRUPT_BASE); + reserve_io_interrupt_vectors(3, 0xfd - ARCH_INTERRUPT_BASE, + INTERRUPT_TYPE_ICI); install_io_interrupt_handler(0xfd - ARCH_INTERRUPT_BASE, &x86_ici_interrupt, NULL, B_NO_LOCK_VECTOR); install_io_interrupt_handler(0xfe - ARCH_INTERRUPT_BASE, &x86_smp_error_interrupt, NULL, B_NO_LOCK_VECTOR); install_io_interrupt_handler(0xff - ARCH_INTERRUPT_BASE, &x86_spurious_interrupt, NULL, B_NO_LOCK_VECTOR); @@ -115,47 +132,95 @@ arch_smp_per_cpu_init(kernel_args *args, int32 cpu) } +void +arch_smp_send_multicast_ici(CPUSet& cpuSet) +{ +#if KDEBUG + if (are_interrupts_enabled()) + panic("arch_smp_send_multicast_ici: called with interrupts enabled"); +#endif + + memory_write_barrier(); + + int32 i = 0; + int32 cpuCount = smp_get_num_cpus(); + + int32 logicalModeCPUs; + if (x2apic_available()) + logicalModeCPUs = cpuCount; + else + logicalModeCPUs = std::min(cpuCount, int32(8)); + + uint32 destination = 0; + for (; i < logicalModeCPUs; i++) { + if (cpuSet.GetBit(i) && i != smp_get_current_cpu()) + destination |= gCPU[i].arch.logical_apic_id; + } + + uint32 mode = ICI_VECTOR | APIC_DELIVERY_MODE_FIXED + | APIC_INTR_COMMAND_1_ASSERT + | APIC_INTR_COMMAND_1_DEST_MODE_LOGICAL + | APIC_INTR_COMMAND_1_DEST_FIELD; + + while (!apic_interrupt_delivered()) + cpu_pause(); + apic_set_interrupt_command(destination, mode); + + for (; i < cpuCount; i++) { + if (cpuSet.GetBit(i)) { + uint32 destination = sCPUAPICIds[i]; + uint32 mode = ICI_VECTOR | APIC_DELIVERY_MODE_FIXED + | APIC_INTR_COMMAND_1_ASSERT + | APIC_INTR_COMMAND_1_DEST_MODE_PHYSICAL + | APIC_INTR_COMMAND_1_DEST_FIELD; + + while (!apic_interrupt_delivered()) + cpu_pause(); + apic_set_interrupt_command(destination, mode); + } + } +} + + void arch_smp_send_broadcast_ici(void) { - uint32 config; - cpu_status state = disable_interrupts(); +#if KDEBUG + if (are_interrupts_enabled()) + panic("arch_smp_send_broadcast_ici: called with interrupts enabled"); +#endif - config = apic_intr_command_1() & APIC_INTR_COMMAND_1_MASK; - apic_set_intr_command_1(config | 0xfd | APIC_DELIVERY_MODE_FIXED - | APIC_INTR_COMMAND_1_ASSERT - | APIC_INTR_COMMAND_1_DEST_MODE_PHYSICAL - | APIC_INTR_COMMAND_1_DEST_ALL_BUT_SELF); + memory_write_barrier(); - restore_interrupts(state); + uint32 mode = ICI_VECTOR | APIC_DELIVERY_MODE_FIXED + | APIC_INTR_COMMAND_1_ASSERT + | APIC_INTR_COMMAND_1_DEST_MODE_PHYSICAL + | APIC_INTR_COMMAND_1_DEST_ALL_BUT_SELF; + + while (!apic_interrupt_delivered()) + cpu_pause(); + apic_set_interrupt_command(0, mode); } void arch_smp_send_ici(int32 target_cpu) { - uint32 config; - uint32 timeout; - cpu_status state; +#if KDEBUG + if (are_interrupts_enabled()) + panic("arch_smp_send_ici: called with interrupts enabled"); +#endif - state = disable_interrupts(); + memory_write_barrier(); - config = apic_intr_command_2() & APIC_INTR_COMMAND_2_MASK; - apic_set_intr_command_2(config | sCPUAPICIds[target_cpu] << 24); + uint32 destination = sCPUAPICIds[target_cpu]; + uint32 mode = ICI_VECTOR | APIC_DELIVERY_MODE_FIXED + | APIC_INTR_COMMAND_1_ASSERT + | APIC_INTR_COMMAND_1_DEST_MODE_PHYSICAL + | APIC_INTR_COMMAND_1_DEST_FIELD; - config = apic_intr_command_1() & APIC_INTR_COMMAND_1_MASK; - apic_set_intr_command_1(config | 0xfd | APIC_DELIVERY_MODE_FIXED - | APIC_INTR_COMMAND_1_ASSERT - | APIC_INTR_COMMAND_1_DEST_MODE_PHYSICAL - | APIC_INTR_COMMAND_1_DEST_FIELD); - - timeout = 100000000; - // wait for message to be sent - while ((apic_intr_command_1() & APIC_DELIVERY_STATUS) != 0 && --timeout != 0) - asm volatile ("pause;"); - - if (timeout == 0) - panic("arch_smp_send_ici: timeout, target_cpu %" B_PRId32, target_cpu); - - restore_interrupts(state); + while (!apic_interrupt_delivered()) + cpu_pause(); + apic_set_interrupt_command(destination, mode); } + diff --git a/src/system/kernel/arch/x86/arch_system_info.cpp b/src/system/kernel/arch/x86/arch_system_info.cpp index 2e227f086b..0544c8105b 100644 --- a/src/system/kernel/arch/x86/arch_system_info.cpp +++ b/src/system/kernel/arch/x86/arch_system_info.cpp @@ -17,9 +17,9 @@ #include -uint32 sCpuType; -int32 sCpuRevision; -int64 sCpuClockSpeed; +enum cpu_vendor sCPUVendor; +uint32 sCPUModel; +int64 sCPUClockSpeed; static bool @@ -29,7 +29,7 @@ get_cpuid_for(cpuid_info *info, uint32 currentCPU, uint32 eaxRegister, if (currentCPU != forCPU) return false; - get_current_cpuid(info, eaxRegister); + get_current_cpuid(info, eaxRegister, 0); return true; } @@ -60,88 +60,74 @@ get_cpuid(cpuid_info *info, uint32 eaxRegister, uint32 forCPU) status_t -arch_get_system_info(system_info *info, size_t size) +arch_system_info_init(struct kernel_args *args) { - info->cpu_type = (cpu_types)sCpuType; - info->cpu_revision = sCpuRevision; + // So far we don't have to care about heterogeneous x86 platforms. + cpu_ent* cpu = get_cpu_struct(); - // - various cpu_info - info->cpu_clock_speed = sCpuClockSpeed; - // - bus_clock_speed -#ifdef __x86_64__ - info->platform_type = B_64_BIT_PC_PLATFORM; -#else - info->platform_type = B_AT_CLONE_PLATFORM; -#endif + switch (cpu->arch.vendor) { + case VENDOR_AMD: + sCPUVendor = B_CPU_VENDOR_AMD; + break; + case VENDOR_CENTAUR: + sCPUVendor = B_CPU_VENDOR_VIA; + break; + case VENDOR_CYRIX: + sCPUVendor = B_CPU_VENDOR_CYRIX; + break; + case VENDOR_INTEL: + sCPUVendor = B_CPU_VENDOR_INTEL; + break; + case VENDOR_NSC: + sCPUVendor = B_CPU_VENDOR_NATIONAL_SEMICONDUCTOR; + break; + case VENDOR_RISE: + sCPUVendor = B_CPU_VENDOR_RISE; + break; + case VENDOR_TRANSMETA: + sCPUVendor = B_CPU_VENDOR_TRANSMETA; + break; + default: + sCPUVendor = B_CPU_VENDOR_UNKNOWN; + break; + } - // ToDo: clock speeds could be retrieved via SMBIOS/DMI + sCPUModel = (cpu->arch.extended_family << 20) + | (cpu->arch.extended_model << 16) | (cpu->arch.type << 12) + | (cpu->arch.family << 8) | (cpu->arch.model << 4) | cpu->arch.stepping; + + sCPUClockSpeed = args->arch_args.cpu_clock_speed; return B_OK; } -status_t -arch_system_info_init(struct kernel_args *args) +void +arch_fill_topology_node(cpu_topology_node_info* node, int32 cpu) { - // This is what you get if the CPU vendor is not recognized - // or the CPU does not support cpuid with eax == 1. - uint32 base; - uint32 model = 0; - cpu_ent *cpu = get_cpu_struct(); + switch (node->type) { + case B_TOPOLOGY_ROOT: +#if __INTEL__ + node->data.root.platform = B_CPU_x86; +#elif __x86_64__ + node->data.root.platform = B_CPU_x86_64; +#else + node->data.root.platform = B_CPU_UNKNOWN; +#endif + break; - switch (cpu->arch.vendor) { - case VENDOR_INTEL: - base = B_CPU_INTEL_x86; + case B_TOPOLOGY_PACKAGE: + node->data.package.vendor = sCPUVendor; + node->data.package.cache_line_size = CACHE_LINE_SIZE; break; - case VENDOR_AMD: - base = B_CPU_AMD_x86; - break; - case VENDOR_CYRIX: - base = B_CPU_CYRIX_x86; - break; - case VENDOR_UMC: - base = B_CPU_INTEL_x86; // XXX - break; - case VENDOR_NEXGEN: - base = B_CPU_INTEL_x86; // XXX - break; - case VENDOR_CENTAUR: - base = B_CPU_VIA_IDT_x86; - break; - case VENDOR_RISE: - base = B_CPU_RISE_x86; - break; - case VENDOR_TRANSMETA: - base = B_CPU_TRANSMETA_x86; - break; - case VENDOR_NSC: - base = B_CPU_NATIONAL_x86; + + case B_TOPOLOGY_CORE: + node->data.core.model = sCPUModel; + node->data.core.default_frequency = sCPUClockSpeed; break; + default: - base = B_CPU_x86; + break; } - - // Any changes to this logic should be replicated to sysinfo.cpp - if (base != B_CPU_x86) { - if (base == B_CPU_INTEL_x86 - || (base == B_CPU_AMD_x86 && cpu->arch.family == 0xF)) { - model = (cpu->arch.extended_family << 20) - + (cpu->arch.extended_model << 16) - + (cpu->arch.family << 4) + cpu->arch.model; - } else { - model = (cpu->arch.family << 4) - + cpu->arch.model; - // Isn't much useful extended family and model information - // yet on other processors. - } - } - - sCpuRevision = (cpu->arch.extended_family << 18) - | (cpu->arch.extended_model << 14) | (cpu->arch.type << 12) - | (cpu->arch.family << 8) | (cpu->arch.model << 4) | cpu->arch.stepping; - - sCpuType = base + model; - sCpuClockSpeed = args->arch_args.cpu_clock_speed; - return B_OK; } @@ -165,3 +151,4 @@ _user_get_cpuid(cpuid_info *userInfo, uint32 eaxRegister, uint32 cpuNum) return status; } + diff --git a/src/system/kernel/arch/x86/arch_thread.cpp b/src/system/kernel/arch/x86/arch_thread.cpp index e7b1298a59..9fbbaa3ad3 100644 --- a/src/system/kernel/arch/x86/arch_thread.cpp +++ b/src/system/kernel/arch/x86/arch_thread.cpp @@ -229,9 +229,8 @@ arch_thread_context_switch(Thread* from, Thread* to) != activePagingStructures) { // update on which CPUs the address space is used int cpu = cpuData->cpu_num; - atomic_and(&activePagingStructures->active_on_cpus, - ~((uint32)1 << cpu)); - atomic_or(&toPagingStructures->active_on_cpus, (uint32)1 << cpu); + activePagingStructures->active_on_cpus.ClearBit(cpu); + toPagingStructures->active_on_cpus.SetBit(cpu); // assign the new paging structures to the CPU toPagingStructures->AddReference(); diff --git a/src/system/kernel/arch/x86/arch_user_debugger.cpp b/src/system/kernel/arch/x86/arch_user_debugger.cpp index 9c1a721b1e..516ed8f340 100644 --- a/src/system/kernel/arch/x86/arch_user_debugger.cpp +++ b/src/system/kernel/arch/x86/arch_user_debugger.cpp @@ -201,10 +201,7 @@ install_breakpoints(const arch_team_debug_info& teamInfo) asm("mov %0, %%dr0" : : "r"(teamInfo.breakpoints[0].address)); asm("mov %0, %%dr1" : : "r"(teamInfo.breakpoints[1].address)); asm("mov %0, %%dr2" : : "r"(teamInfo.breakpoints[2].address)); -#ifdef __x86_64__ asm("mov %0, %%dr3" : : "r"(teamInfo.breakpoints[3].address)); - // DR3 is used to hold the current Thread* on 32. -#endif // enable breakpoints asm("mov %0, %%dr7" : : "r"(teamInfo.dr7)); diff --git a/src/system/kernel/arch/x86/ioapic.cpp b/src/system/kernel/arch/x86/ioapic.cpp index 20bf4a48ed..734a2dedea 100644 --- a/src/system/kernel/arch/x86/ioapic.cpp +++ b/src/system/kernel/arch/x86/ioapic.cpp @@ -18,6 +18,7 @@ #include #include +#include #include // to gain access to the ACPICA types @@ -26,9 +27,9 @@ //#define TRACE_IOAPIC #ifdef TRACE_IOAPIC -# define TRACE(x) dprintf x +# define TRACE(...) dprintf(__VA_ARGS__) #else -# define TRACE(x) ; +# define TRACE(...) (void)0 #endif @@ -242,6 +243,30 @@ ioapic_end_of_interrupt(int32 num) } +static void +ioapic_assign_interrupt_to_cpu(int32 gsi, int32 cpu) +{ + if (gsi < ISA_INTERRUPT_COUNT && sSourceOverrides[gsi] != 0) + gsi = sSourceOverrides[gsi]; + + struct ioapic* ioapic = find_ioapic(gsi); + if (ioapic == NULL) + return; + + uint32 apicid = x86_get_cpu_apic_id(cpu); + + uint8 pin = gsi - ioapic->global_interrupt_base; + TRACE("ioapic_assign_interrupt_to_cpu: gsi %ld (io-apic %u pin %u) to" + " cpu %ld (apic_id %lu)\n", gsi, ioapic->number, pin, cpu, apicid); + + uint64 entry = ioapic_read_64(*ioapic, IO_APIC_REDIRECTION_TABLE + pin * 2); + entry &= ~(uint64(IO_APIC_DESTINATION_FIELD_MASK) + << IO_APIC_DESTINATION_FIELD_SHIFT); + entry |= uint64(apicid) << IO_APIC_DESTINATION_FIELD_SHIFT; + ioapic_write_64(*ioapic, IO_APIC_REDIRECTION_TABLE + pin * 2, entry, false); +} + + static void ioapic_enable_io_interrupt(int32 gsi) { @@ -255,9 +280,11 @@ ioapic_enable_io_interrupt(int32 gsi) if (ioapic == NULL) return; + x86_set_irq_source(gsi, IRQ_SOURCE_IOAPIC); + uint8 pin = gsi - ioapic->global_interrupt_base; - TRACE(("ioapic_enable_io_interrupt: gsi %ld -> io-apic %u pin %u\n", - gsi, ioapic->number, pin)); + TRACE("ioapic_enable_io_interrupt: gsi %ld -> io-apic %u pin %u\n", + gsi, ioapic->number, pin); uint64 entry = ioapic_read_64(*ioapic, IO_APIC_REDIRECTION_TABLE + pin * 2); entry &= ~IO_APIC_INTERRUPT_MASKED; @@ -273,8 +300,8 @@ ioapic_disable_io_interrupt(int32 gsi) return; uint8 pin = gsi - ioapic->global_interrupt_base; - TRACE(("ioapic_disable_io_interrupt: gsi %ld -> io-apic %u pin %u\n", - gsi, ioapic->number, pin)); + TRACE("ioapic_disable_io_interrupt: gsi %ld -> io-apic %u pin %u\n", + gsi, ioapic->number, pin); uint64 entry = ioapic_read_64(*ioapic, IO_APIC_REDIRECTION_TABLE + pin * 2); entry |= IO_APIC_INTERRUPT_MASKED; @@ -290,8 +317,8 @@ ioapic_configure_io_interrupt(int32 gsi, uint32 config) return; uint8 pin = gsi - ioapic->global_interrupt_base; - TRACE(("ioapic_configure_io_interrupt: gsi %ld -> io-apic %u pin %u; " - "config 0x%08lx\n", gsi, ioapic->number, pin, config)); + TRACE("ioapic_configure_io_interrupt: gsi %ld -> io-apic %u pin %u; " + "config 0x%08lx\n", gsi, ioapic->number, pin, config); ioapic_configure_pin(*ioapic, pin, gsi, config, IO_APIC_DELIVERY_MODE_FIXED); @@ -310,7 +337,7 @@ ioapic_map_ioapic(struct ioapic& ioapic, phys_addr_t physicalAddress) return ioapic.register_area; } - TRACE(("mapped io-apic %u to %p\n", ioapic.number, ioapic.registers)); + TRACE("mapped io-apic %u to %p\n", ioapic.number, ioapic.registers); ioapic.version = ioapic_read_32(ioapic, IO_APIC_VERSION); if (ioapic.version == 0xffffffff) { @@ -650,7 +677,8 @@ ioapic_init(kernel_args* args) &ioapic_configure_io_interrupt, &ioapic_is_spurious_interrupt, &ioapic_is_level_triggered_interrupt, - &ioapic_end_of_interrupt + &ioapic_end_of_interrupt, + &ioapic_assign_interrupt_to_cpu, }; if (args->arch_args.apic == NULL) @@ -774,7 +802,13 @@ ioapic_init(kernel_args* args) current = sIOAPICs; while (current != NULL) { reserve_io_interrupt_vectors(current->max_redirection_entry + 1, - current->global_interrupt_base); + current->global_interrupt_base, INTERRUPT_TYPE_IRQ); + + for (int32 i = 0; i < current->max_redirection_entry + 1; i++) { + x86_set_irq_source(current->global_interrupt_base + i, + IRQ_SOURCE_IOAPIC); + } + current = current->next; } diff --git a/src/system/kernel/arch/x86/msi.cpp b/src/system/kernel/arch/x86/msi.cpp index 54f4cffc28..4578e14d19 100644 --- a/src/system/kernel/arch/x86/msi.cpp +++ b/src/system/kernel/arch/x86/msi.cpp @@ -5,12 +5,20 @@ #include #include +#include #include #include #include +struct MSIConfiguration { + uint64* fAddress; + uint16* fData; +}; + +static MSIConfiguration sMSIConfigurations[NUM_IO_VECTORS]; + static bool sMSISupported = false; static uint32 sBootCPUAPICId = 0; @@ -44,7 +52,8 @@ msi_allocate_vectors(uint8 count, uint8 *startVector, uint64 *address, return B_UNSUPPORTED; long vector; - status_t result = allocate_io_interrupt_vectors(count, &vector); + status_t result = allocate_io_interrupt_vectors(count, &vector, + INTERRUPT_TYPE_IRQ); if (result != B_OK) return result; @@ -53,6 +62,10 @@ msi_allocate_vectors(uint8 count, uint8 *startVector, uint64 *address, return B_NO_MEMORY; } + sMSIConfigurations[vector].fAddress = address; + sMSIConfigurations[vector].fData = data; + x86_set_irq_source(vector, IRQ_SOURCE_MSI); + *startVector = (uint8)vector; *address = MSI_ADDRESS_BASE | (sBootCPUAPICId << MSI_DESTINATION_ID_SHIFT) | MSI_NO_REDIRECTION | MSI_DESTINATION_MODE_PHYSICAL; @@ -78,3 +91,15 @@ msi_free_vectors(uint8 count, uint8 startVector) free_io_interrupt_vectors(count, startVector); } + + +void +msi_assign_interrupt_to_cpu(uint8 irq, int32 cpu) +{ + uint32 apic_id = x86_get_cpu_apic_id(cpu); + + uint64* address = sMSIConfigurations[irq].fAddress; + *address = MSI_ADDRESS_BASE | (apic_id << MSI_DESTINATION_ID_SHIFT) + | MSI_NO_REDIRECTION | MSI_DESTINATION_MODE_PHYSICAL; +} + diff --git a/src/system/kernel/arch/x86/paging/32bit/X86PagingMethod32Bit.cpp b/src/system/kernel/arch/x86/paging/32bit/X86PagingMethod32Bit.cpp index be91ed524a..64c93cf8be 100644 --- a/src/system/kernel/arch/x86/paging/32bit/X86PagingMethod32Bit.cpp +++ b/src/system/kernel/arch/x86/paging/32bit/X86PagingMethod32Bit.cpp @@ -15,6 +15,7 @@ #include +#include #include #include #include @@ -36,6 +37,10 @@ #endif +#define MAX_INITIAL_POOLS \ + (ROUNDUP(SMP_MAX_CPUS * TOTAL_SLOTS_PER_CPU + EXTRA_SLOTS, 1024) / 1024) + + using X86LargePhysicalPageMapper::PhysicalPageSlot; @@ -60,7 +65,7 @@ public: addr_t virtualAddress); public: - static PhysicalPageSlotPool sInitialPhysicalPagePool; + static PhysicalPageSlotPool sInitialPhysicalPagePool[MAX_INITIAL_POOLS]; private: area_id fDataArea; @@ -71,7 +76,8 @@ private: X86PagingMethod32Bit::PhysicalPageSlotPool - X86PagingMethod32Bit::PhysicalPageSlotPool::sInitialPhysicalPagePool; + X86PagingMethod32Bit::PhysicalPageSlotPool::sInitialPhysicalPagePool[ + MAX_INITIAL_POOLS]; X86PagingMethod32Bit::PhysicalPageSlotPool::~PhysicalPageSlotPool() @@ -287,20 +293,23 @@ X86PagingMethod32Bit::Init(kernel_args* args, X86PagingStructures32Bit::StaticInit(); - // create the initial pool for the physical page mapper - PhysicalPageSlotPool* pool - = new(&PhysicalPageSlotPool::sInitialPhysicalPagePool) - PhysicalPageSlotPool; - status_t error = pool->InitInitial(args); - if (error != B_OK) { - panic("X86PagingMethod32Bit::Init(): Failed to create initial pool " - "for physical page mapper!"); - return error; + // create the initial pools for the physical page mapper + int32 poolCount = _GetInitialPoolCount(); + PhysicalPageSlotPool* pool = PhysicalPageSlotPool::sInitialPhysicalPagePool; + + for (int32 i = 0; i < poolCount; i++) { + new(&pool[i]) PhysicalPageSlotPool; + status_t error = pool[i].InitInitial(args); + if (error != B_OK) { + panic("X86PagingMethod32Bit::Init(): Failed to create initial pool " + "for physical page mapper!"); + return error; + } } // create physical page mapper - large_memory_physical_page_ops_init(args, pool, fPhysicalPageMapper, - fKernelPhysicalPageMapper); + large_memory_physical_page_ops_init(args, pool, poolCount, sizeof(*pool), + fPhysicalPageMapper, fKernelPhysicalPageMapper); // TODO: Select the best page mapper! // enable global page feature if available @@ -323,7 +332,6 @@ X86PagingMethod32Bit::InitPostArea(kernel_args* args) // now that the vm is initialized, create an area that represents // the page hole void *temp; - status_t error; area_id area; // unmap the page hole hack we were using before @@ -337,10 +345,13 @@ X86PagingMethod32Bit::InitPostArea(kernel_args* args) if (area < B_OK) return area; - error = PhysicalPageSlotPool::sInitialPhysicalPagePool - .InitInitialPostArea(args); - if (error != B_OK) - return error; + int32 poolCount = _GetInitialPoolCount(); + for (int32 i = 0; i < poolCount; i++) { + status_t error = PhysicalPageSlotPool::sInitialPhysicalPagePool[i] + .InitInitialPostArea(args); + if (error != B_OK) + return error; + } return B_OK; } @@ -517,6 +528,15 @@ X86PagingMethod32Bit::PutPageTableEntryInTable(page_table_entry* entry, } +inline int32 +X86PagingMethod32Bit::_GetInitialPoolCount() +{ + int32 requiredSlots = smp_get_num_cpus() * TOTAL_SLOTS_PER_CPU + + EXTRA_SLOTS; + return (requiredSlots + 1023) / 1024; +} + + /*static*/ void X86PagingMethod32Bit::_EarlyPreparePageTables(page_table_entry* pageTables, addr_t address, size_t size) diff --git a/src/system/kernel/arch/x86/paging/32bit/X86PagingMethod32Bit.h b/src/system/kernel/arch/x86/paging/32bit/X86PagingMethod32Bit.h index f781f7df1f..96cb50605c 100644 --- a/src/system/kernel/arch/x86/paging/32bit/X86PagingMethod32Bit.h +++ b/src/system/kernel/arch/x86/paging/32bit/X86PagingMethod32Bit.h @@ -80,6 +80,8 @@ private: friend struct PhysicalPageSlotPool; private: + inline int32 _GetInitialPoolCount(); + static void _EarlyPreparePageTables( page_table_entry* pageTables, addr_t address, size_t size); @@ -108,7 +110,7 @@ X86PagingMethod32Bit::Method() X86PagingMethod32Bit::SetPageTableEntry(page_table_entry* entry, page_table_entry newEntry) { - return atomic_set((int32*)entry, newEntry); + return atomic_get_and_set((int32*)entry, newEntry); } diff --git a/src/system/kernel/arch/x86/paging/64bit/X86PagingMethod64Bit.h b/src/system/kernel/arch/x86/paging/64bit/X86PagingMethod64Bit.h index e834434c78..ac1bfebbc4 100644 --- a/src/system/kernel/arch/x86/paging/64bit/X86PagingMethod64Bit.h +++ b/src/system/kernel/arch/x86/paging/64bit/X86PagingMethod64Bit.h @@ -116,7 +116,7 @@ X86PagingMethod64Bit::Method() /*static*/ inline uint64 X86PagingMethod64Bit::SetTableEntry(uint64* entry, uint64 newEntry) { - return atomic_set64((int64*)entry, newEntry); + return atomic_get_and_set64((int64*)entry, newEntry); } diff --git a/src/system/kernel/arch/x86/paging/X86PagingStructures.cpp b/src/system/kernel/arch/x86/paging/X86PagingStructures.cpp index 4a2d9ee9ad..2844391341 100644 --- a/src/system/kernel/arch/x86/paging/X86PagingStructures.cpp +++ b/src/system/kernel/arch/x86/paging/X86PagingStructures.cpp @@ -9,8 +9,7 @@ X86PagingStructures::X86PagingStructures() : - ref_count(1), - active_on_cpus(0) + ref_count(1) { } diff --git a/src/system/kernel/arch/x86/paging/X86PagingStructures.h b/src/system/kernel/arch/x86/paging/X86PagingStructures.h index fe8b9d9a94..2744b0cef0 100644 --- a/src/system/kernel/arch/x86/paging/X86PagingStructures.h +++ b/src/system/kernel/arch/x86/paging/X86PagingStructures.h @@ -14,11 +14,13 @@ #include +#include + struct X86PagingStructures : DeferredDeletable { phys_addr_t pgdir_phys; - vint32 ref_count; - vint32 active_on_cpus; + int32 ref_count; + CPUSet active_on_cpus; // mask indicating on which CPUs the map is currently used X86PagingStructures(); diff --git a/src/system/kernel/arch/x86/paging/X86VMTranslationMap.cpp b/src/system/kernel/arch/x86/paging/X86VMTranslationMap.cpp index a9768653ef..5ed05001ea 100644 --- a/src/system/kernel/arch/x86/paging/X86VMTranslationMap.cpp +++ b/src/system/kernel/arch/x86/paging/X86VMTranslationMap.cpp @@ -113,9 +113,10 @@ X86VMTranslationMap::Flush() restore_interrupts(state); int cpu = smp_get_current_cpu(); - uint32 cpuMask = PagingStructures()->active_on_cpus - & ~((uint32)1 << cpu); - if (cpuMask != 0) { + CPUSet cpuMask = PagingStructures()->active_on_cpus; + cpuMask.ClearBit(cpu); + + if (!cpuMask.IsEmpty()) { smp_send_multicast_ici(cpuMask, SMP_MSG_USER_INVALIDATE_PAGES, 0, 0, 0, NULL, SMP_MSG_FLAG_SYNC); } @@ -132,9 +133,10 @@ X86VMTranslationMap::Flush() SMP_MSG_FLAG_SYNC); } else { int cpu = smp_get_current_cpu(); - uint32 cpuMask = PagingStructures()->active_on_cpus - & ~((uint32)1 << cpu); - if (cpuMask != 0) { + CPUSet cpuMask = PagingStructures()->active_on_cpus; + cpuMask.ClearBit(cpu); + + if (!cpuMask.IsEmpty()) { smp_send_multicast_ici(cpuMask, SMP_MSG_INVALIDATE_PAGE_LIST, (addr_t)fInvalidPages, fInvalidPagesCount, 0, NULL, SMP_MSG_FLAG_SYNC); diff --git a/src/system/kernel/arch/x86/paging/pae/X86PagingMethodPAE.cpp b/src/system/kernel/arch/x86/paging/pae/X86PagingMethodPAE.cpp index e4ee9bccb0..089f0ccb84 100644 --- a/src/system/kernel/arch/x86/paging/pae/X86PagingMethodPAE.cpp +++ b/src/system/kernel/arch/x86/paging/pae/X86PagingMethodPAE.cpp @@ -15,6 +15,7 @@ #include +#include #include #include #include @@ -40,6 +41,12 @@ #if B_HAIKU_PHYSICAL_BITS == 64 +#define MAX_INITIAL_POOLS \ + (ROUNDUP(SMP_MAX_CPUS * TOTAL_SLOTS_PER_CPU + EXTRA_SLOTS, \ + kPAEPageTableEntryCount) \ + / kPAEPageTableEntryCount) + + using X86LargePhysicalPageMapper::PhysicalPageSlot; @@ -364,7 +371,7 @@ public: addr_t virtualAddress); public: - static PhysicalPageSlotPool sInitialPhysicalPagePool; + static PhysicalPageSlotPool sInitialPhysicalPagePool[MAX_INITIAL_POOLS]; private: area_id fDataArea; @@ -375,7 +382,8 @@ private: X86PagingMethodPAE::PhysicalPageSlotPool - X86PagingMethodPAE::PhysicalPageSlotPool::sInitialPhysicalPagePool; + X86PagingMethodPAE::PhysicalPageSlotPool::sInitialPhysicalPagePool[ + MAX_INITIAL_POOLS]; X86PagingMethodPAE::PhysicalPageSlotPool::~PhysicalPageSlotPool() @@ -585,20 +593,23 @@ X86PagingMethodPAE::Init(kernel_args* args, fEarlyPageStructuresSize, fKernelVirtualPageDirs, fKernelPhysicalPageDirs, fFreeVirtualSlot, fFreeVirtualSlotPTE); - // create the initial pool for the physical page mapper - PhysicalPageSlotPool* pool - = new(&PhysicalPageSlotPool::sInitialPhysicalPagePool) - PhysicalPageSlotPool; - status_t error = pool->InitInitial(this, args); - if (error != B_OK) { - panic("X86PagingMethodPAE::Init(): Failed to create initial pool " - "for physical page mapper!"); - return error; + // create the initial pools for the physical page mapper + int32 poolCount = _GetInitialPoolCount(); + PhysicalPageSlotPool* pool = PhysicalPageSlotPool::sInitialPhysicalPagePool; + + for (int32 i = 0; i < poolCount; i++) { + new(&pool[i]) PhysicalPageSlotPool; + status_t error = pool[i].InitInitial(this, args); + if (error != B_OK) { + panic("X86PagingMethodPAE::Init(): Failed to create initial pool " + "for physical page mapper!"); + return error; + } } // create physical page mapper - large_memory_physical_page_ops_init(args, pool, fPhysicalPageMapper, - fKernelPhysicalPageMapper); + large_memory_physical_page_ops_init(args, pool, poolCount, sizeof(*pool), + fPhysicalPageMapper, fKernelPhysicalPageMapper); *_physicalPageMapper = fPhysicalPageMapper; return B_OK; @@ -615,11 +626,14 @@ X86PagingMethodPAE::InitPostArea(kernel_args* args) if (area < B_OK) return area; - // let the initial page pool create areas for its structures - status_t error = PhysicalPageSlotPool::sInitialPhysicalPagePool - .InitInitialPostArea(args); - if (error != B_OK) - return error; + // let the initial page pools create areas for its structures + int32 poolCount = _GetInitialPoolCount(); + for (int32 i = 0; i < poolCount; i++) { + status_t error = PhysicalPageSlotPool::sInitialPhysicalPagePool[i] + .InitInitialPostArea(args); + if (error != B_OK) + return error; + } // The early physical page mapping mechanism is no longer needed. Unmap the // slot. @@ -884,6 +898,16 @@ X86PagingMethodPAE::Free32BitPage(void* address, phys_addr_t physicalAddress, } +inline int32 +X86PagingMethodPAE::_GetInitialPoolCount() +{ + int32 requiredSlots = smp_get_num_cpus() * TOTAL_SLOTS_PER_CPU + + EXTRA_SLOTS; + return (requiredSlots + kPAEPageTableEntryCount - 1) + / kPAEPageTableEntryCount; +} + + bool X86PagingMethodPAE::_EarlyQuery(addr_t virtualAddress, phys_addr_t* _physicalAddress) diff --git a/src/system/kernel/arch/x86/paging/pae/X86PagingMethodPAE.h b/src/system/kernel/arch/x86/paging/pae/X86PagingMethodPAE.h index 6d6b1ed1ab..44715e541b 100644 --- a/src/system/kernel/arch/x86/paging/pae/X86PagingMethodPAE.h +++ b/src/system/kernel/arch/x86/paging/pae/X86PagingMethodPAE.h @@ -100,6 +100,8 @@ private: friend struct PhysicalPageSlotPool; private: + inline int32 _GetInitialPoolCount(); + bool _EarlyQuery(addr_t virtualAddress, phys_addr_t* _physicalAddress); pae_page_table_entry* _EarlyGetPageTable(phys_addr_t address); @@ -158,7 +160,7 @@ X86PagingMethodPAE::PageDirEntryForAddress( X86PagingMethodPAE::SetPageTableEntry(pae_page_table_entry* entry, pae_page_table_entry newEntry) { - return atomic_set64((int64*)entry, newEntry); + return atomic_get_and_set64((int64*)entry, newEntry); } diff --git a/src/system/kernel/arch/x86/paging/x86_physical_page_mapper_large_memory.cpp b/src/system/kernel/arch/x86/paging/x86_physical_page_mapper_large_memory.cpp index b317f92e28..07c9446fdc 100644 --- a/src/system/kernel/arch/x86/paging/x86_physical_page_mapper_large_memory.cpp +++ b/src/system/kernel/arch/x86/paging/x86_physical_page_mapper_large_memory.cpp @@ -48,12 +48,6 @@ // a little longer, thus avoiding re-mapping. #define SLOTS_PER_TRANSLATION_MAP 4 -#define USER_SLOTS_PER_CPU 16 -#define KERNEL_SLOTS_PER_CPU 16 -#define TOTAL_SLOTS_PER_CPU (USER_SLOTS_PER_CPU \ - + KERNEL_SLOTS_PER_CPU + 1) - // one slot is for use in interrupts - using X86LargePhysicalPageMapper::PhysicalPageSlot; using X86LargePhysicalPageMapper::PhysicalPageSlotPool; @@ -111,7 +105,7 @@ private: struct page_slot { PhysicalPageSlot* slot; phys_addr_t physicalAddress; - cpu_mask_t valid; + CPUSet valid; }; page_slot fSlots[SLOTS_PER_TRANSLATION_MAP]; @@ -125,9 +119,10 @@ public: LargeMemoryPhysicalPageMapper(); status_t Init(kernel_args* args, - PhysicalPageSlotPool* initialPool, - TranslationMapPhysicalPageMapper*& - _kernelPageMapper); + PhysicalPageSlotPool* initialPools, + int32 initalPoolCount, size_t poolSize, + TranslationMapPhysicalPageMapper*& + _kernelPageMapper); virtual status_t CreateTranslationMapPhysicalPageMapper( TranslationMapPhysicalPageMapper** _mapper); @@ -173,7 +168,7 @@ private: PhysicalPageSlot* fDebugSlot; PhysicalPageSlotPool* fInitialPool; LargeMemoryTranslationMapPhysicalPageMapper fKernelMapper; - PhysicalPageOpsCPUData fPerCPUData[B_MAX_CPU_COUNT]; + PhysicalPageOpsCPUData fPerCPUData[SMP_MAX_CPUS]; }; static LargeMemoryPhysicalPageMapper sPhysicalPageMapper; @@ -394,10 +389,10 @@ LargeMemoryTranslationMapPhysicalPageMapper::GetPageTableAt( page_slot& slot = fSlots[i]; if (slot.physicalAddress == physicalAddress) { fNextSlot = (i + 1) & (fSlotCount - 1); - if ((slot.valid & (1 << currentCPU)) == 0) { + if (!slot.valid.GetBit(currentCPU)) { // not valid on this CPU -- invalidate the TLB entry invalidate_TLB(slot.slot->address); - slot.valid |= 1 << currentCPU; + slot.valid.SetBit(currentCPU); } return (void*)slot.slot->address; } @@ -409,7 +404,8 @@ LargeMemoryTranslationMapPhysicalPageMapper::GetPageTableAt( slot.physicalAddress = physicalAddress; slot.slot->Map(physicalAddress); - slot.valid = 1 << currentCPU; + slot.valid.ClearAll(); + slot.valid.SetBit(currentCPU); return (void*)slot.slot->address; } @@ -428,11 +424,16 @@ LargeMemoryPhysicalPageMapper::LargeMemoryPhysicalPageMapper() status_t LargeMemoryPhysicalPageMapper::Init(kernel_args* args, - PhysicalPageSlotPool* initialPool, + PhysicalPageSlotPool* initialPools, int32 initialPoolCount, size_t poolSize, TranslationMapPhysicalPageMapper*& _kernelPageMapper) { - fInitialPool = initialPool; - fNonEmptyPools.Add(fInitialPool); + ASSERT(initialPoolCount >= 1); + + fInitialPool = initialPools; + for (int32 i = 0; i < initialPoolCount; i++) { + uint8* pointer = (uint8*)initialPools + i * poolSize; + fNonEmptyPools.Add((PhysicalPageSlotPool*)pointer); + } // get the debug slot GetSlot(true, fDebugSlot); @@ -755,12 +756,14 @@ LargeMemoryPhysicalPageMapper::GetSlotQueue(int32 cpu, bool user) status_t large_memory_physical_page_ops_init(kernel_args* args, - X86LargePhysicalPageMapper::PhysicalPageSlotPool* initialPool, + X86LargePhysicalPageMapper::PhysicalPageSlotPool* initialPools, + int32 initialPoolCount, size_t poolSize, X86PhysicalPageMapper*& _pageMapper, TranslationMapPhysicalPageMapper*& _kernelPageMapper) { new(&sPhysicalPageMapper) LargeMemoryPhysicalPageMapper; - sPhysicalPageMapper.Init(args, initialPool, _kernelPageMapper); + sPhysicalPageMapper.Init(args, initialPools, initialPoolCount, poolSize, + _kernelPageMapper); _pageMapper = &sPhysicalPageMapper; return B_OK; diff --git a/src/system/kernel/arch/x86/paging/x86_physical_page_mapper_large_memory.h b/src/system/kernel/arch/x86/paging/x86_physical_page_mapper_large_memory.h index 93986fb15f..8e695417cb 100644 --- a/src/system/kernel/arch/x86/paging/x86_physical_page_mapper_large_memory.h +++ b/src/system/kernel/arch/x86/paging/x86_physical_page_mapper_large_memory.h @@ -11,6 +11,15 @@ #include +#define USER_SLOTS_PER_CPU 16 +#define KERNEL_SLOTS_PER_CPU 16 +#define TOTAL_SLOTS_PER_CPU (USER_SLOTS_PER_CPU \ + + KERNEL_SLOTS_PER_CPU + 1) + // one slot is for use in interrupts + +#define EXTRA_SLOTS 2 + + class TranslationMapPhysicalPageMapper; class X86PhysicalPageMapper; struct kernel_args; @@ -53,7 +62,8 @@ protected: status_t large_memory_physical_page_ops_init(kernel_args* args, - X86LargePhysicalPageMapper::PhysicalPageSlotPool* initialPool, + X86LargePhysicalPageMapper::PhysicalPageSlotPool* initialPools, + int32 initialPoolCount, size_t poolSize, X86PhysicalPageMapper*& _pageMapper, TranslationMapPhysicalPageMapper*& _kernelPageMapper); diff --git a/src/system/kernel/arch/x86/pic.cpp b/src/system/kernel/arch/x86/pic.cpp index 7e086312c2..a802ff32d9 100644 --- a/src/system/kernel/arch/x86/pic.cpp +++ b/src/system/kernel/arch/x86/pic.cpp @@ -196,7 +196,8 @@ pic_init() &pic_configure_io_interrupt, &pic_is_spurious_interrupt, &pic_is_level_triggered_interrupt, - &pic_end_of_interrupt + &pic_end_of_interrupt, + NULL }; // Start initialization sequence for the master and slave PICs @@ -231,7 +232,7 @@ pic_init() TRACE(("PIC level trigger mode: 0x%08lx\n", sLevelTriggeredInterrupts)); - reserve_io_interrupt_vectors(16, 0); + reserve_io_interrupt_vectors(16, 0, INTERRUPT_TYPE_EXCEPTION); // make the pic controller the current one arch_int_set_interrupt_controller(picController); diff --git a/src/system/kernel/arch/x86/timers/x86_apic.cpp b/src/system/kernel/arch/x86/timers/x86_apic.cpp index 3569e75aba..568cd65244 100644 --- a/src/system/kernel/arch/x86/timers/x86_apic.cpp +++ b/src/system/kernel/arch/x86/timers/x86_apic.cpp @@ -14,7 +14,6 @@ #include #include -#include #include "apic_timer.h" @@ -106,7 +105,8 @@ apic_timer_init(struct kernel_args *args) sApicTicsPerSec = args->arch_args.apic_time_cv_factor; - reserve_io_interrupt_vectors(1, 0xfb - ARCH_INTERRUPT_BASE); + reserve_io_interrupt_vectors(1, 0xfb - ARCH_INTERRUPT_BASE, + INTERRUPT_TYPE_LOCAL_IRQ); install_io_interrupt_handler(0xfb - ARCH_INTERRUPT_BASE, &apic_timer_interrupt, NULL, B_NO_LOCK_VECTOR); diff --git a/src/system/kernel/condition_variable.cpp b/src/system/kernel/condition_variable.cpp index 47215606b1..85c7a3f87b 100644 --- a/src/system/kernel/condition_variable.cpp +++ b/src/system/kernel/condition_variable.cpp @@ -134,15 +134,11 @@ ConditionVariableEntry::Wait(uint32 flags, bigtime_t timeout) conditionLocker.Unlock(); - SpinLocker schedulerLocker(gSchedulerLock); - status_t error; if ((flags & (B_RELATIVE_TIMEOUT | B_ABSOLUTE_TIMEOUT)) != 0) - error = thread_block_with_timeout_locked(flags, timeout); + error = thread_block_with_timeout(flags, timeout); else - error = thread_block_locked(thread_get_current_thread()); - - schedulerLocker.Unlock(); + error = thread_block(); conditionLocker.Lock(); @@ -221,13 +217,11 @@ ConditionVariable::Publish(const void* object, const char* objectType) void -ConditionVariable::Unpublish(bool schedulerLocked) +ConditionVariable::Unpublish() { ASSERT(fObject != NULL); - InterruptsLocker _; - SpinLocker schedulerLocker(schedulerLocked ? NULL : &gSchedulerLock); - SpinLocker locker(sConditionVariablesLock); + InterruptsSpinLocker locker(sConditionVariablesLock); #if KDEBUG ConditionVariable* variable = sConditionVariableHash.Lookup(fObject); @@ -263,8 +257,7 @@ ConditionVariable::Wait(uint32 flags, bigtime_t timeout) /*static*/ void -ConditionVariable::NotifyOne(const void* object, bool schedulerLocked, - status_t result) +ConditionVariable::NotifyOne(const void* object, status_t result) { InterruptsSpinLocker locker(sConditionVariablesLock); ConditionVariable* variable = sConditionVariableHash.Lookup(object); @@ -272,13 +265,12 @@ ConditionVariable::NotifyOne(const void* object, bool schedulerLocked, if (variable == NULL) return; - variable->NotifyOne(schedulerLocked, result); + variable->NotifyOne(result); } /*static*/ void -ConditionVariable::NotifyAll(const void* object, bool schedulerLocked, - status_t result) +ConditionVariable::NotifyAll(const void* object, status_t result) { InterruptsSpinLocker locker(sConditionVariablesLock); ConditionVariable* variable = sConditionVariableHash.Lookup(object); @@ -286,7 +278,7 @@ ConditionVariable::NotifyAll(const void* object, bool schedulerLocked, if (variable == NULL) return; - variable->NotifyAll(schedulerLocked, result); + variable->NotifyAll(result); } @@ -322,11 +314,9 @@ ConditionVariable::Dump() const void -ConditionVariable::_Notify(bool all, bool schedulerLocked, status_t result) +ConditionVariable::_Notify(bool all, status_t result) { - InterruptsLocker _; - SpinLocker schedulerLocker(schedulerLocked ? NULL : &gSchedulerLock); - SpinLocker locker(sConditionVariablesLock); + InterruptsSpinLocker locker(sConditionVariablesLock); if (!fEntries.IsEmpty()) { if (result > B_OK) { @@ -352,8 +342,10 @@ ConditionVariable::_NotifyLocked(bool all, status_t result) if (entry->fWaitStatus <= 0) continue; - if (entry->fWaitStatus == STATUS_WAITING) + if (entry->fWaitStatus == STATUS_WAITING) { + SpinLocker _(entry->fThread->scheduler_lock); thread_unblock_locked(entry->fThread, result); + } entry->fWaitStatus = result; diff --git a/src/system/kernel/cpu.cpp b/src/system/kernel/cpu.cpp index 44bff7e25d..c984f353d1 100644 --- a/src/system/kernel/cpu.cpp +++ b/src/system/kernel/cpu.cpp @@ -1,4 +1,5 @@ /* + * Copyright 2013, Paweł Dziepak, pdziepak@quarnos.org. * Copyright 2002-2008, Axel Dörfler, axeld@pinc-software.de. * Distributed under the terms of the MIT License. * @@ -14,13 +15,23 @@ #include +#include +#include + #include +#include #include #include /* global per-cpu structure */ -cpu_ent gCPU[MAX_BOOT_CPUS]; +cpu_ent gCPU[SMP_MAX_CPUS]; + +uint32 gCPUCacheLevelCount; +static cpu_topology_node sCPUTopology; + +static cpufreq_module_info* sCPUPerformanceModule; +static cpuidle_module_info* sCPUIdleModule; static spinlock sSetCpuLock; @@ -46,10 +57,84 @@ cpu_init_post_vm(kernel_args *args) } +static void +load_cpufreq_module() +{ + void* cookie = open_module_list(CPUFREQ_MODULES_PREFIX); + + while (true) { + char name[B_FILE_NAME_LENGTH]; + size_t nameLength = sizeof(name); + cpufreq_module_info* current = NULL; + + if (read_next_module_name(cookie, name, &nameLength) != B_OK) + break; + + if (get_module(name, (module_info**)¤t) == B_OK) { + dprintf("found cpufreq module: %s\n", name); + + if (sCPUPerformanceModule != NULL) { + if (sCPUPerformanceModule->rank < current->rank) { + put_module(sCPUPerformanceModule->info.name); + sCPUPerformanceModule = current; + } else + put_module(name); + } else + sCPUPerformanceModule = current; + } + } + + close_module_list(cookie); + + if (sCPUPerformanceModule == NULL) + dprintf("no valid cpufreq module found\n"); +} + + +static void +load_cpuidle_module() +{ + void* cookie = open_module_list(CPUIDLE_MODULES_PREFIX); + + while (true) { + char name[B_FILE_NAME_LENGTH]; + size_t nameLength = sizeof(name); + cpuidle_module_info* current = NULL; + + if (read_next_module_name(cookie, name, &nameLength) != B_OK) + break; + + if (get_module(name, (module_info**)¤t) == B_OK) { + dprintf("found cpuidle module: %s\n", name); + + if (sCPUIdleModule != NULL) { + if (sCPUIdleModule->rank < current->rank) { + put_module(sCPUIdleModule->info.name); + sCPUIdleModule = current; + } else + put_module(name); + } else + sCPUIdleModule = current; + } + } + + close_module_list(cookie); + + if (sCPUIdleModule == NULL) + dprintf("no valid cpuidle module found\n"); +} + + status_t cpu_init_post_modules(kernel_args *args) { - return arch_cpu_init_post_modules(args); + status_t result = arch_cpu_init_post_modules(args); + if (result != B_OK) + return result; + + load_cpufreq_module(); + load_cpuidle_module(); + return B_OK; } @@ -61,6 +146,9 @@ cpu_preboot_init_percpu(kernel_args *args, int curr_cpu) memset(&gCPU[curr_cpu], 0, sizeof(gCPU[curr_cpu])); gCPU[curr_cpu].cpu_num = curr_cpu; + list_init(&gCPU[curr_cpu].irqs); + B_INITIALIZE_SPINLOCK(&gCPU[curr_cpu].irqs_lock); + return arch_cpu_preboot_init_percpu(args, curr_cpu); } @@ -71,12 +159,15 @@ cpu_get_active_time(int32 cpu) if (cpu < 0 || cpu > smp_get_num_cpus()) return 0; - // We need to grab the scheduler lock here, because the thread activity - // time is not maintained atomically (because there is no need to). + bigtime_t activeTime; + uint32 count; - InterruptsSpinLocker schedulerLocker(gSchedulerLock); + do { + count = acquire_read_seqlock(&gCPU[cpu].active_time_lock); + activeTime = gCPU[cpu].active_time; + } while (!release_read_seqlock(&gCPU[cpu].active_time_lock, count)); - return gCPU[cpu].active_time; + return activeTime; } @@ -87,6 +178,170 @@ clear_caches(void *address, size_t length, uint32 flags) } +static status_t +cpu_create_topology_node(cpu_topology_node* node, int32* maxID, int32 id) +{ + cpu_topology_level level = static_cast(node->level - 1); + ASSERT(level >= 0); + + cpu_topology_node* newNode = new(std::nothrow) cpu_topology_node; + if (newNode == NULL) + return B_NO_MEMORY; + node->children[id] = newNode; + + newNode->level = level; + if (level != CPU_TOPOLOGY_SMT) { + newNode->children_count = maxID[level - 1]; + newNode->children + = new(std::nothrow) cpu_topology_node*[maxID[level - 1]]; + if (newNode->children == NULL) + return B_NO_MEMORY; + + memset(newNode->children, 0, + maxID[level - 1] * sizeof(cpu_topology_node*)); + } else { + newNode->children_count = 0; + newNode->children = NULL; + } + + return B_OK; +} + + +static void +cpu_rebuild_topology_tree(cpu_topology_node* node, int32* lastID) +{ + if (node->children == NULL) + return; + + int32 count = 0; + for (int32 i = 0; i < node->children_count; i++) { + if (node->children[i] == NULL) + continue; + + if (count != i) + node->children[count] = node->children[i]; + + if (node->children[count]->level != CPU_TOPOLOGY_SMT) + node->children[count]->id = lastID[node->children[count]->level]++; + + cpu_rebuild_topology_tree(node->children[count], lastID); + count++; + } + node->children_count = count; +} + + +status_t +cpu_build_topology_tree(void) +{ + sCPUTopology.level = CPU_TOPOLOGY_LEVELS; + + int32 maxID[CPU_TOPOLOGY_LEVELS]; + memset(&maxID, 0, sizeof(maxID)); + + const int32 kCPUCount = smp_get_num_cpus(); + for (int32 i = 0; i < kCPUCount; i++) { + for (int32 j = 0; j < CPU_TOPOLOGY_LEVELS; j++) + maxID[j] = max_c(maxID[j], gCPU[i].topology_id[j]); + } + + for (int32 j = 0; j < CPU_TOPOLOGY_LEVELS; j++) + maxID[j]++; + + sCPUTopology.children_count = maxID[CPU_TOPOLOGY_LEVELS - 1]; + sCPUTopology.children + = new(std::nothrow) cpu_topology_node*[maxID[CPU_TOPOLOGY_LEVELS - 1]]; + if (sCPUTopology.children == NULL) + return B_NO_MEMORY; + memset(sCPUTopology.children, 0, + maxID[CPU_TOPOLOGY_LEVELS - 1] * sizeof(cpu_topology_node*)); + + for (int32 i = 0; i < kCPUCount; i++) { + cpu_topology_node* node = &sCPUTopology; + for (int32 j = CPU_TOPOLOGY_LEVELS - 1; j >= 0; j--) { + int32 id = gCPU[i].topology_id[j]; + if (node->children[id] == NULL) { + status_t result = cpu_create_topology_node(node, maxID, id); + if (result != B_OK) + return result; + } + + node = node->children[id]; + } + + ASSERT(node->level == CPU_TOPOLOGY_SMT); + node->id = i; + } + + int32 lastID[CPU_TOPOLOGY_LEVELS]; + memset(&lastID, 0, sizeof(lastID)); + cpu_rebuild_topology_tree(&sCPUTopology, lastID); + + return B_OK; +} + + +const cpu_topology_node* +get_cpu_topology(void) +{ + return &sCPUTopology; +} + + +void +cpu_set_scheduler_mode(enum scheduler_mode mode) +{ + if (sCPUPerformanceModule != NULL) + sCPUPerformanceModule->cpufreq_set_scheduler_mode(mode); + if (sCPUIdleModule != NULL) + sCPUIdleModule->cpuidle_set_scheduler_mode(mode); +} + + +status_t +increase_cpu_performance(int delta) +{ + if (sCPUPerformanceModule != NULL) + return sCPUPerformanceModule->cpufreq_increase_performance(delta); + return B_NOT_SUPPORTED; +} + + +status_t +decrease_cpu_performance(int delta) +{ + if (sCPUPerformanceModule != NULL) + return sCPUPerformanceModule->cpufreq_decrease_performance(delta); + return B_NOT_SUPPORTED; +} + + +void +cpu_idle(void) +{ +#if KDEBUG + if (!are_interrupts_enabled()) + panic("cpu_idle() called with interrupts disabled."); +#endif + + if (sCPUIdleModule != NULL) + sCPUIdleModule->cpuidle_idle(); + else + arch_cpu_idle(); +} + + +void +cpu_wait(int32* variable, int32 test) +{ + if (sCPUIdleModule != NULL) + sCPUIdleModule->cpuidle_wait(variable, test); + else + arch_cpu_pause(); +} + + // #pragma mark - @@ -110,8 +365,6 @@ _user_cpu_enabled(int32 cpu) status_t _user_set_cpu_enabled(int32 cpu, bool enabled) { - status_t status = B_OK; - cpu_status state; int32 i, count; if (cpu < 0 || cpu >= smp_get_num_cpus()) @@ -120,8 +373,7 @@ _user_set_cpu_enabled(int32 cpu, bool enabled) // We need to lock here to make sure that no one can disable // the last CPU - state = disable_interrupts(); - acquire_spinlock(&sSetCpuLock); + InterruptsSpinLocker locker(sSetCpuLock); if (!enabled) { // check if this is the last CPU to be disabled @@ -131,14 +383,37 @@ _user_set_cpu_enabled(int32 cpu, bool enabled) } if (count == 1) - status = B_NOT_ALLOWED; + return B_NOT_ALLOWED; } - if (status == B_OK) - gCPU[cpu].disabled = !enabled; + bool oldState = gCPU[cpu].disabled; - release_spinlock(&sSetCpuLock); - restore_interrupts(state); - return status; + if (oldState != !enabled) + scheduler_set_cpu_enabled(cpu, enabled); + + if (!enabled) { + if (smp_get_current_cpu() == cpu) { + locker.Unlock(); + thread_yield(); + locker.Lock(); + } + + // someone reenabled the CPU while we were rescheduling + if (!gCPU[cpu].disabled) + return B_OK; + + ASSERT(smp_get_current_cpu() != cpu); + while (!thread_is_idle_thread(gCPU[cpu].running_thread)) { + locker.Unlock(); + thread_yield(); + locker.Lock(); + + if (!gCPU[cpu].disabled) + return B_OK; + ASSERT(smp_get_current_cpu() != cpu); + } + } + + return B_OK; } diff --git a/src/system/kernel/debug/debug.cpp b/src/system/kernel/debug/debug.cpp index 15adaba629..da74437805 100644 --- a/src/system/kernel/debug/debug.cpp +++ b/src/system/kernel/debug/debug.cpp @@ -81,7 +81,7 @@ void call_modules_hook(bool enter); static void syslog_write(const char* text, int32 length, bool notify); -static arch_debug_registers sDebugRegisters[B_MAX_CPU_COUNT]; +static arch_debug_registers sDebugRegisters[SMP_MAX_CPUS]; static debug_page_fault_info sPageFaultInfo; @@ -139,11 +139,11 @@ static int32 sCurrentLine = 0; static debugger_demangle_module_info* sDemangleModule; static Thread* sDebuggedThread; -static vint32 sInDebugger = 0; +static int32 sInDebugger = 0; static bool sPreviousDprintfState; static volatile bool sHandOverKDL = false; -static vint32 sHandOverKDLToCPU = -1; -static bool sCPUTrapped[B_MAX_CPU_COUNT]; +static int32 sHandOverKDLToCPU = -1; +static bool sCPUTrapped[SMP_MAX_CPUS]; #define distance(a, b) ((a) < (b) ? (b) - (a) : (a) - (b)) @@ -703,7 +703,7 @@ kgetc(void) } } - PAUSE(); + cpu_pause(); } } @@ -1007,8 +1007,8 @@ hand_over_kernel_debugger() // hand over to another CPU without us noticing. Since this is only // initiated by the user, it is harmless, though. sHandOverKDL = true; - while (sHandOverKDLToCPU >= 0) - PAUSE(); + while (atomic_get(&sHandOverKDLToCPU) >= 0) + cpu_wait(&sHandOverKDLToCPU, -1); } diff --git a/src/system/kernel/debug/system_profiler.cpp b/src/system/kernel/debug/system_profiler.cpp index c2d75492cc..af3570737c 100644 --- a/src/system/kernel/debug/system_profiler.cpp +++ b/src/system/kernel/debug/system_profiler.cpp @@ -199,8 +199,8 @@ private: bool fWaitObjectNotificationsRequested; Thread* volatile fWaitingProfilerThread; bool fProfilingActive; - bool fReentered[B_MAX_CPU_COUNT]; - CPUProfileData fCPUData[B_MAX_CPU_COUNT]; + bool fReentered[SMP_MAX_CPUS]; + CPUProfileData fCPUData[SMP_MAX_CPUS]; WaitObject* fWaitObjectBuffer; int32 fWaitObjectCount; WaitObjectList fUsedWaitObjects; @@ -220,6 +220,7 @@ SystemProfiler::_MaybeNotifyProfilerThreadLocked() int cpu = smp_get_current_cpu(); fReentered[cpu] = true; + InterruptsSpinLocker _(fWaitingProfilerThread->scheduler_lock); thread_unblock_locked(fWaitingProfilerThread, B_OK); fWaitingProfilerThread = NULL; @@ -234,7 +235,6 @@ SystemProfiler::_MaybeNotifyProfilerThread() if (fWaitingProfilerThread == NULL) return; - InterruptsSpinLocker schedulerLocker(gSchedulerLock); SpinLocker locker(fLock); _MaybeNotifyProfilerThreadLocked(); @@ -298,18 +298,15 @@ SystemProfiler::~SystemProfiler() // inactive. InterruptsSpinLocker locker(fLock); if (fWaitingProfilerThread != NULL) { - InterruptsSpinLocker schedulerLocker(gSchedulerLock); - thread_unblock_locked(fWaitingProfilerThread, B_OK); + thread_unblock(fWaitingProfilerThread, B_OK); fWaitingProfilerThread = NULL; } fProfilingActive = false; locker.Unlock(); // stop scheduler listening - if (fSchedulerNotificationsRequested) { - InterruptsSpinLocker schedulerLocker(gSchedulerLock); + if (fSchedulerNotificationsRequested) scheduler_remove_listener(this); - } // stop wait object listening if (fWaitObjectNotificationsRequested) { @@ -499,8 +496,6 @@ SystemProfiler::Init() fThreadNotificationsEnabled = true; } - InterruptsSpinLocker schedulerLocker(gSchedulerLock); - fProfilingActive = true; // start scheduler and wait object listening @@ -522,8 +517,6 @@ SystemProfiler::Init() } } - schedulerLocker.Unlock(); - // I/O scheduling if ((fFlags & B_SYSTEM_PROFILER_IO_SCHEDULING_EVENTS) != 0) { IOSchedulerRoster* roster = IOSchedulerRoster::Default(); @@ -572,12 +565,9 @@ SystemProfiler::NextBuffer(size_t bytesRead, uint64* _droppedEvents) Thread* thread = thread_get_current_thread(); fWaitingProfilerThread = thread; - InterruptsSpinLocker schedulerLocker(gSchedulerLock); - thread_prepare_to_block(thread, B_CAN_INTERRUPT, THREAD_BLOCK_TYPE_OTHER, "system profiler buffer"); - schedulerLocker.Unlock(); locker.Unlock(); status_t error = thread_block_with_timeout(B_RELATIVE_TIMEOUT, 1000000); diff --git a/src/system/kernel/debug/user_debugger.cpp b/src/system/kernel/debug/user_debugger.cpp index a3f1915878..a4eb75ebc3 100644 --- a/src/system/kernel/debug/user_debugger.cpp +++ b/src/system/kernel/debug/user_debugger.cpp @@ -53,7 +53,7 @@ static port_id sDefaultDebuggerPort = -1; // accessed atomically -static timer sProfilingTimers[B_MAX_CPU_COUNT]; +static timer sProfilingTimers[SMP_MAX_CPUS]; // a profiling timer for each CPU -- used when a profiled thread is running // on that CPU @@ -440,7 +440,7 @@ finish_debugger_change(Team* team) ConditionVariable* condition = team->debug_info.debugger_changed_condition; team->debug_info.debugger_changed_condition = NULL; - condition->NotifyAll(false); + condition->NotifyAll(); } @@ -2901,7 +2901,7 @@ _user_debug_thread(thread_id threadID) // resume/interrupt the thread, if necessary threadDebugInfoLocker.Unlock(); - SpinLocker schedulerLocker(gSchedulerLock); + SpinLocker schedulerLocker(thread->scheduler_lock); switch (thread->state) { case B_THREAD_SUSPENDED: @@ -2916,6 +2916,10 @@ _user_debug_thread(thread_id threadID) // about to acquire a semaphore (before // thread_prepare_to_block()), we won't interrupt it. // Maybe we should rather send a signal (SIGTRAP). + schedulerLocker.Unlock(); + + schedulerLocker.SetTo(thread_get_current_thread()->scheduler_lock, + false); scheduler_reschedule_if_necessary_locked(); break; } diff --git a/src/system/kernel/device_manager/IOCache.cpp b/src/system/kernel/device_manager/IOCache.cpp index a65e515d28..7cd834b8a5 100644 --- a/src/system/kernel/device_manager/IOCache.cpp +++ b/src/system/kernel/device_manager/IOCache.cpp @@ -205,10 +205,10 @@ IOCache::OperationCompleted(IOOperation* operation, status_t status, { if (status == B_OK) { // always fail in case of partial transfers - ((Operation*)operation)->finishedCondition.NotifyAll(false, + ((Operation*)operation)->finishedCondition.NotifyAll( transferredBytes == operation->Length() ? B_OK : B_ERROR); } else - ((Operation*)operation)->finishedCondition.NotifyAll(false, status); + ((Operation*)operation)->finishedCondition.NotifyAll(status); } @@ -498,7 +498,7 @@ IOCache::_DoOperation(Operation& operation) status_t error = fIOCallback(fIOCallbackData, &operation); if (error != B_OK) { - operation.finishedCondition.NotifyAll(false, error); + operation.finishedCondition.NotifyAll(error); // removes the entry from the variable return error; } diff --git a/src/system/kernel/fs/EntryCache.cpp b/src/system/kernel/fs/EntryCache.cpp index 2c44d60e88..e9a6a14db9 100644 --- a/src/system/kernel/fs/EntryCache.cpp +++ b/src/system/kernel/fs/EntryCache.cpp @@ -165,7 +165,8 @@ EntryCache::Lookup(ino_t dirID, const char* name, ino_t& _nodeID) if (entry == NULL) return false; - int32 oldGeneration = atomic_set(&entry->generation, fCurrentGeneration); + int32 oldGeneration = atomic_get_and_set(&entry->generation, + fCurrentGeneration); if (oldGeneration == fCurrentGeneration || entry->index < 0) { // The entry is already in the current generation or is being moved to // it by another thread. diff --git a/src/system/kernel/fs/EntryCache.h b/src/system/kernel/fs/EntryCache.h index 91d74043ed..e197426eec 100644 --- a/src/system/kernel/fs/EntryCache.h +++ b/src/system/kernel/fs/EntryCache.h @@ -34,14 +34,14 @@ struct EntryCacheEntry { EntryCacheEntry* hash_link; ino_t node_id; ino_t dir_id; - vint32 generation; - vint32 index; + int32 generation; + int32 index; char name[1]; }; struct EntryCacheGeneration { - vint32 next_index; + int32 next_index; EntryCacheEntry** entries; EntryCacheGeneration(); diff --git a/src/system/kernel/fs/Vnode.cpp b/src/system/kernel/fs/Vnode.cpp index 890e29bf9f..cc71aae551 100644 --- a/src/system/kernel/fs/Vnode.cpp +++ b/src/system/kernel/fs/Vnode.cpp @@ -88,6 +88,5 @@ vnode::_WakeUpLocker() atomic_and(&fFlags, ~kFlagsWaitingLocker); // and wake it up - InterruptsSpinLocker threadLocker(gSchedulerLock); - thread_unblock_locked(waiter->thread, B_OK); + thread_unblock(waiter->thread, B_OK); } diff --git a/src/system/kernel/fs/Vnode.h b/src/system/kernel/fs/Vnode.h index a40cf65059..d4ef8fd3ff 100644 --- a/src/system/kernel/fs/Vnode.h +++ b/src/system/kernel/fs/Vnode.h @@ -104,7 +104,7 @@ private: void _WakeUpLocker(); private: - vint32 fFlags; + int32 fFlags; static Bucket sBuckets[kBucketCount]; }; diff --git a/src/system/kernel/fs/fifo.cpp b/src/system/kernel/fs/fifo.cpp index 09d2e3f97c..15d45ffe04 100644 --- a/src/system/kernel/fs/fifo.cpp +++ b/src/system/kernel/fs/fifo.cpp @@ -99,8 +99,7 @@ public: TRACE("ReadRequest %p::Notify(), fNotified %d\n", this, fNotified); if (!fNotified) { - SpinLocker schedulerLocker(gSchedulerLock); - thread_unblock_locked(fThread, status); + thread_unblock(fThread, status); fNotified = true; } } diff --git a/src/system/kernel/fs/unused_vnodes.h b/src/system/kernel/fs/unused_vnodes.h index ca866debab..5f5bb490b6 100644 --- a/src/system/kernel/fs/unused_vnodes.h +++ b/src/system/kernel/fs/unused_vnodes.h @@ -30,15 +30,15 @@ const static uint32 kMaxUnusedVnodes = 8192; */ static mutex sUnusedVnodesLock = MUTEX_INITIALIZER("unused vnodes"); static list sUnusedVnodeList; -static vuint32 sUnusedVnodes = 0; +static uint32 sUnusedVnodes = 0; static const int32 kMaxHotVnodes = 1024; static rw_lock sHotVnodesLock = RW_LOCK_INITIALIZER("hot vnodes"); static Vnode* sHotVnodes[kMaxHotVnodes]; -static vint32 sNextHotVnodeIndex = 0; +static int32 sNextHotVnodeIndex = 0; static const int32 kUnusedVnodesCheckInterval = 64; -static vint32 sUnusedVnodesCheckCount = 0; +static int32 sUnusedVnodesCheckCount = 0; /*! Must be called with sHotVnodesLock write-locked. @@ -48,7 +48,7 @@ flush_hot_vnodes_locked() { MutexLocker unusedLocker(sUnusedVnodesLock); - int32 count = std::min((int32)sNextHotVnodeIndex, kMaxHotVnodes); + int32 count = std::min(sNextHotVnodeIndex, kMaxHotVnodes); for (int32 i = 0; i < count; i++) { Vnode* vnode = sHotVnodes[i]; if (vnode == NULL) @@ -87,7 +87,7 @@ vnode_unused(Vnode* vnode) bool result = false; int32 checkCount = atomic_add(&sUnusedVnodesCheckCount, 1); if (checkCount == kUnusedVnodesCheckInterval) { - uint32 unusedCount = sUnusedVnodes; + uint32 unusedCount = atomic_get((int32*)&sUnusedVnodes); if (unusedCount > kMaxUnusedVnodes && low_resource_state( B_KERNEL_RESOURCE_PAGES | B_KERNEL_RESOURCE_MEMORY) @@ -164,7 +164,7 @@ vnode_to_be_freed(Vnode* vnode) if (vnode->IsHot()) { // node is hot -- remove it from the array // TODO: Maybe better completely flush the array while at it? - int32 count = sNextHotVnodeIndex; + int32 count = atomic_get(&sNextHotVnodeIndex); count = std::min(count, kMaxHotVnodes); for (int32 i = 0; i < count; i++) { if (sHotVnodes[i] == vnode) { diff --git a/src/system/kernel/heap.cpp b/src/system/kernel/heap.cpp index a2815bff6a..9a6ab41571 100644 --- a/src/system/kernel/heap.cpp +++ b/src/system/kernel/heap.cpp @@ -187,9 +187,9 @@ static const heap_class sHeapClasses[HEAP_CLASS_COUNT] = { static uint32 sHeapCount; -static heap_allocator *sHeaps[HEAP_CLASS_COUNT * B_MAX_CPU_COUNT]; -static uint32 *sLastGrowRequest[HEAP_CLASS_COUNT * B_MAX_CPU_COUNT]; -static uint32 *sLastHandledGrowRequest[HEAP_CLASS_COUNT * B_MAX_CPU_COUNT]; +static heap_allocator *sHeaps[HEAP_CLASS_COUNT * SMP_MAX_CPUS]; +static uint32 *sLastGrowRequest[HEAP_CLASS_COUNT * SMP_MAX_CPUS]; +static uint32 *sLastHandledGrowRequest[HEAP_CLASS_COUNT * SMP_MAX_CPUS]; static heap_allocator *sVIPHeap; static heap_allocator *sGrowHeap = NULL; diff --git a/src/system/kernel/image.cpp b/src/system/kernel/image.cpp index e76cc60118..c948b69f86 100644 --- a/src/system/kernel/image.cpp +++ b/src/system/kernel/image.cpp @@ -370,16 +370,20 @@ notify_loading_app(status_t result, bool suspend) // we're done with the team stuff, get the scheduler lock instead teamLocker.Unlock(); - InterruptsSpinLocker schedulerLocker(gSchedulerLock); + Thread* thread = loadingInfo->thread; + InterruptsSpinLocker schedulerLocker(thread->scheduler_lock); // wake up the waiting thread - if (loadingInfo->thread->state == B_THREAD_SUSPENDED) - scheduler_enqueue_in_run_queue(loadingInfo->thread); + if (thread->state == B_THREAD_SUSPENDED) + scheduler_enqueue_in_run_queue(thread); + schedulerLocker.Unlock(); // suspend ourselves, if desired if (suspend) { - thread_get_current_thread()->next_state = B_THREAD_SUSPENDED; - scheduler_reschedule(); + Thread* thread = thread_get_current_thread(); + InterruptsSpinLocker schedulerLocker(thread->scheduler_lock); + + scheduler_reschedule(B_THREAD_SUSPENDED); } } } diff --git a/src/system/kernel/int.cpp b/src/system/kernel/int.cpp index 6f9de63a76..b34ba01c7f 100644 --- a/src/system/kernel/int.cpp +++ b/src/system/kernel/int.cpp @@ -1,4 +1,7 @@ /* + * Copyright 2013, Paweł Dziepak, pdziepak@quarnos.org. + * Distributed under the terms of the MIT License. + * Copyright 2011, Michael Lotz, mmlr@mlotz.ch. * Distributed under the terms of the MIT License. * @@ -20,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -51,6 +55,15 @@ struct io_vector { spinlock vector_lock; int32 enable_count; bool no_lock_vector; + interrupt_type type; + + spinlock load_lock; + bigtime_t last_measure_time; + bigtime_t last_measure_active; + int32 load; + + irq_assignment* assigned_cpu; + #if DEBUG_INTERRUPTS int64 handled_count; int64 unhandled_count; @@ -59,8 +72,11 @@ struct io_vector { #endif }; -static struct io_vector sVectors[NUM_IO_VECTORS]; +static int32 sLastCPU; + +static io_vector sVectors[NUM_IO_VECTORS]; static bool sAllocatedIOInterruptVectors[NUM_IO_VECTORS]; +static irq_assignment sVectorCPUAssignments[NUM_IO_VECTORS]; static mutex sIOInterruptVectorAllocationLock = MUTEX_INITIALIZER("io_interrupt_vector_allocation"); @@ -116,6 +132,43 @@ dump_int_statistics(int argc, char **argv) #endif +static int +dump_int_load(int argc, char** argv) +{ + static const char* typeNames[] + = { "exception", "irq", "local irq", "syscall", "ici", "unknown" }; + + for (int i = 0; i < NUM_IO_VECTORS; i++) { + if (!B_SPINLOCK_IS_LOCKED(&sVectors[i].vector_lock) + && sVectors[i].handler_list == NULL + && sVectors[i].enable_count == 0) + continue; + + kprintf("int %3d, type %s, enabled %" B_PRId32 ", load %" B_PRId32 + "%%", i, typeNames[min_c(sVectors[i].type, + INTERRUPT_TYPE_UNKNOWN)], + sVectors[i].enable_count, + sVectors[i].assigned_cpu != NULL + ? sVectors[i].assigned_cpu->load / 10 : 0); + + if (sVectors[i].type == INTERRUPT_TYPE_IRQ) { + ASSERT(sVectors[i].assigned_cpu != NULL); + + if (sVectors[i].assigned_cpu->cpu != -1) + kprintf(", cpu %" B_PRId32, sVectors[i].assigned_cpu->cpu); + else + kprintf(", cpu -"); + } + + if (B_SPINLOCK_IS_LOCKED(&sVectors[i].vector_lock)) + kprintf(", ACTIVE"); + kprintf("\n"); + } + + return 0; +} + + // #pragma mark - private kernel API @@ -145,6 +198,13 @@ int_init_post_vm(kernel_args* args) B_INITIALIZE_SPINLOCK(&sVectors[i].vector_lock); sVectors[i].enable_count = 0; sVectors[i].no_lock_vector = false; + sVectors[i].type = INTERRUPT_TYPE_UNKNOWN; + + B_INITIALIZE_SPINLOCK(&sVectors[i].load_lock); + sVectors[i].last_measure_time = 0; + sVectors[i].last_measure_active = 0; + sVectors[i].load = 0; + #if DEBUG_INTERRUPTS sVectors[i].handled_count = 0; sVectors[i].unhandled_count = 0; @@ -152,6 +212,12 @@ int_init_post_vm(kernel_args* args) sVectors[i].ignored_count = 0; #endif sVectors[i].handler_list = NULL; + + sVectorCPUAssignments[i].irq = i; + sVectorCPUAssignments[i].count = 1; + sVectorCPUAssignments[i].handlers_count = 0; + sVectorCPUAssignments[i].load = 0; + sVectorCPUAssignments[i].cpu = -1; } #if DEBUG_INTERRUPTS @@ -159,6 +225,9 @@ int_init_post_vm(kernel_args* args) "list interrupt statistics"); #endif + add_debugger_command("int_load", &dump_int_load, + "list interrupt usage statistics"); + return arch_int_init_post_vm(args); } @@ -179,6 +248,23 @@ int_init_post_device_manager(kernel_args* args) } +static void +update_int_load(int i) +{ + if (!try_acquire_spinlock(&sVectors[i].load_lock)) + return; + + int32 oldLoad = sVectors[i].load; + compute_load(sVectors[i].last_measure_time, sVectors[i].last_measure_active, + sVectors[i].load, system_time()); + + if (oldLoad != sVectors[i].load) + atomic_add(&sVectors[i].assigned_cpu->load, sVectors[i].load - oldLoad); + + release_spinlock(&sVectors[i].load_lock); +} + + /*! Actually process an interrupt via the handlers registered for that vector (IRQ). */ @@ -189,6 +275,12 @@ int_io_interrupt_handler(int vector, bool levelTriggered) struct io_handler* io; bool handled = false; + bigtime_t start = system_time(); + + // exceptions and syscalls have their own handlers + ASSERT(sVectors[vector].type != INTERRUPT_TYPE_EXCEPTION + && sVectors[vector].type != INTERRUPT_TYPE_SYSCALL); + if (!sVectors[vector].no_lock_vector) acquire_spinlock(&sVectors[vector].vector_lock); @@ -267,6 +359,22 @@ int_io_interrupt_handler(int vector, bool levelTriggered) if (!sVectors[vector].no_lock_vector) release_spinlock(&sVectors[vector].vector_lock); + SpinLocker vectorLocker(sVectors[vector].load_lock); + bigtime_t deltaTime = system_time() - start; + sVectors[vector].last_measure_active += deltaTime; + vectorLocker.Unlock(); + + cpu_ent* cpu = get_cpu_struct(); + if (sVectors[vector].type == INTERRUPT_TYPE_IRQ + || sVectors[vector].type == INTERRUPT_TYPE_ICI + || sVectors[vector].type == INTERRUPT_TYPE_LOCAL_IRQ) { + cpu->interrupt_time += deltaTime; + if (sVectors[vector].type == INTERRUPT_TYPE_IRQ) + cpu->irq_time += deltaTime; + } + + update_int_load(vector); + if (levelTriggered) return status; @@ -300,6 +408,25 @@ restore_interrupts(cpu_status status) } +static +uint32 assign_cpu(void) +{ + const cpu_topology_node* node; + do { + int32 nextID = atomic_add(&sLastCPU, 1); + node = get_cpu_topology(); + + while (node->level != CPU_TOPOLOGY_SMT) { + int levelSize = node->children_count; + node = node->children[nextID % levelSize]; + nextID /= levelSize; + } + } while (gCPU[node->id].disabled); + + return node->id; +} + + /*! Install a handler to be called when an interrupt is triggered for the given interrupt number with \a data as the argument. */ @@ -334,6 +461,22 @@ install_io_interrupt_handler(long vector, interrupt_handler handler, void *data, state = disable_interrupts(); acquire_spinlock(&sVectors[vector].vector_lock); + // Initial attempt to balance IRQs, the scheduler will correct this + // if some cores end up being overloaded. + if (sVectors[vector].type == INTERRUPT_TYPE_IRQ + && sVectors[vector].handler_list == NULL + && sVectors[vector].assigned_cpu->cpu == -1) { + + int32 cpuID = assign_cpu(); + arch_int_assign_to_cpu(vector, cpuID); + sVectors[vector].assigned_cpu->cpu = cpuID; + + cpu_ent* cpu = &gCPU[cpuID]; + SpinLocker _(cpu->irqs_lock); + atomic_add(&sVectors[vector].assigned_cpu->handlers_count, 1); + list_add_item(&cpu->irqs, sVectors[vector].assigned_cpu); + } + if ((flags & B_NO_HANDLED_INFO) != 0 && sVectors[vector].handler_list != NULL) { // The driver registering this interrupt handler doesn't know @@ -373,6 +516,7 @@ install_io_interrupt_handler(long vector, interrupt_handler handler, void *data, sVectors[vector].no_lock_vector = true; release_spinlock(&sVectors[vector].vector_lock); + restore_interrupts(state); return B_OK; @@ -418,6 +562,35 @@ remove_io_interrupt_handler(long vector, interrupt_handler handler, void *data) last = io; } + if (sVectors[vector].handler_list == NULL + && sVectors[vector].type == INTERRUPT_TYPE_IRQ + && sVectors[vector].assigned_cpu != NULL + && sVectors[vector].assigned_cpu->handlers_count > 0) { + + int32 oldHandlersCount + = atomic_add(&sVectors[vector].assigned_cpu->handlers_count, -1); + + if (oldHandlersCount == 1) { + int32 oldCPU; + SpinLocker locker; + cpu_ent* cpu; + + do { + locker.Unlock(); + + oldCPU = sVectors[vector].assigned_cpu->cpu; + + ASSERT(oldCPU != -1); + cpu = &gCPU[oldCPU]; + + locker.SetTo(cpu->irqs_lock, false); + } while (sVectors[vector].assigned_cpu->cpu != oldCPU); + + sVectors[vector].assigned_cpu->cpu = -1; + list_remove_item(&cpu->irqs, sVectors[vector].assigned_cpu); + } + } + release_spinlock(&sVectors[vector].vector_lock); restore_interrupts(state); @@ -435,7 +608,7 @@ remove_io_interrupt_handler(long vector, interrupt_handler handler, void *data) vectors using allocate_io_interrupt_vectors() instead. */ status_t -reserve_io_interrupt_vectors(long count, long startVector) +reserve_io_interrupt_vectors(long count, long startVector, interrupt_type type) { MutexLocker locker(&sIOInterruptVectorAllocationLock); @@ -448,6 +621,10 @@ reserve_io_interrupt_vectors(long count, long startVector) return B_BUSY; } + sVectors[startVector + i].type = type; + sVectors[startVector + i].assigned_cpu + = &sVectorCPUAssignments[startVector + i]; + sVectorCPUAssignments[startVector + i].count = 1; sAllocatedIOInterruptVectors[startVector + i] = true; } @@ -462,7 +639,8 @@ reserve_io_interrupt_vectors(long count, long startVector) The first vector to be used is returned in \a startVector on success. */ status_t -allocate_io_interrupt_vectors(long count, long *startVector) +allocate_io_interrupt_vectors(long count, long *startVector, + interrupt_type type) { MutexLocker locker(&sIOInterruptVectorAllocationLock); @@ -491,8 +669,14 @@ allocate_io_interrupt_vectors(long count, long *startVector) return B_NO_MEMORY; } - for (long i = 0; i < count; i++) + for (long i = 0; i < count; i++) { + sVectors[vector + i].type = type; + sVectors[vector + i].assigned_cpu = &sVectorCPUAssignments[vector]; sAllocatedIOInterruptVectors[vector + i] = true; + } + + sVectorCPUAssignments[vector].irq = vector; + sVectorCPUAssignments[vector].count = count; *startVector = vector; dprintf("allocate_io_interrupt_vectors: allocated %ld vectors starting " @@ -524,6 +708,36 @@ free_io_interrupt_vectors(long count, long startVector) startVector + i); } + sVectors[startVector + i].assigned_cpu = NULL; sAllocatedIOInterruptVectors[startVector + i] = false; } } + + +void assign_io_interrupt_to_cpu(long vector, int32 newCPU) +{ + ASSERT(sVectors[vector].type == INTERRUPT_TYPE_IRQ); + + int32 oldCPU = sVectors[vector].assigned_cpu->cpu; + + if (newCPU == -1) + newCPU = assign_cpu(); + + if (newCPU == oldCPU) + return; + + ASSERT(oldCPU != -1); + cpu_ent* cpu = &gCPU[oldCPU]; + + SpinLocker locker(cpu->irqs_lock); + sVectors[vector].assigned_cpu->cpu = -1; + list_remove_item(&cpu->irqs, sVectors[vector].assigned_cpu); + locker.Unlock(); + + cpu = &gCPU[newCPU]; + locker.SetTo(cpu->irqs_lock, false); + sVectors[vector].assigned_cpu->cpu = newCPU; + arch_int_assign_to_cpu(vector, newCPU); + list_add_item(&cpu->irqs, sVectors[vector].assigned_cpu); +} + diff --git a/src/system/kernel/locks/lock.cpp b/src/system/kernel/locks/lock.cpp index caebd36c5b..facf6268e5 100644 --- a/src/system/kernel/locks/lock.cpp +++ b/src/system/kernel/locks/lock.cpp @@ -149,7 +149,7 @@ recursive_lock_unlock(recursive_lock *lock) static status_t -rw_lock_wait(rw_lock* lock, bool writer) +rw_lock_wait(rw_lock* lock, bool writer, InterruptsSpinLocker& locker) { // enqueue in waiter list rw_lock_waiter waiter; @@ -166,7 +166,12 @@ rw_lock_wait(rw_lock* lock, bool writer) // block thread_prepare_to_block(waiter.thread, 0, THREAD_BLOCK_TYPE_RW_LOCK, lock); - return thread_block_locked(waiter.thread); + locker.Unlock(); + + status_t result = thread_block(); + + locker.Lock(); + return result; } @@ -192,7 +197,8 @@ rw_lock_unblock(rw_lock* lock) lock->holder = waiter->thread->id; // unblock thread - thread_unblock_locked(waiter->thread, B_OK); + thread_unblock(waiter->thread, B_OK); + waiter->thread = NULL; return RW_LOCK_WRITER_COUNT_BASE; } @@ -208,7 +214,8 @@ rw_lock_unblock(rw_lock* lock) readerCount++; // unblock thread - thread_unblock_locked(waiter->thread, B_OK); + thread_unblock(waiter->thread, B_OK); + waiter->thread = NULL; } while ((waiter = lock->waiters) != NULL && !waiter->writer); @@ -224,6 +231,7 @@ rw_lock_init(rw_lock* lock, const char* name) { lock->name = name; lock->waiters = NULL; + B_INITIALIZE_SPINLOCK(&lock->lock); lock->holder = -1; lock->count = 0; lock->owner_count = 0; @@ -241,6 +249,7 @@ rw_lock_init_etc(rw_lock* lock, const char* name, uint32 flags) { lock->name = (flags & RW_LOCK_FLAG_CLONE_NAME) != 0 ? strdup(name) : name; lock->waiters = NULL; + B_INITIALIZE_SPINLOCK(&lock->lock); lock->holder = -1; lock->count = 0; lock->owner_count = 0; @@ -260,7 +269,7 @@ rw_lock_destroy(rw_lock* lock) ? (char*)lock->name : NULL; // unblock all waiters - InterruptsSpinLocker locker(gSchedulerLock); + InterruptsSpinLocker locker(lock->lock); #if KDEBUG if (lock->waiters != NULL && thread_get_current_thread_id() @@ -280,7 +289,7 @@ rw_lock_destroy(rw_lock* lock) lock->waiters = waiter->next; // unblock thread - thread_unblock_locked(waiter->thread, B_ERROR); + thread_unblock(waiter->thread, B_ERROR); } lock->name = NULL; @@ -296,7 +305,7 @@ rw_lock_destroy(rw_lock* lock) status_t _rw_lock_read_lock(rw_lock* lock) { - InterruptsSpinLocker locker(gSchedulerLock); + InterruptsSpinLocker locker(lock->lock); // We might be the writer ourselves. if (lock->holder == thread_get_current_thread_id()) { @@ -320,7 +329,7 @@ _rw_lock_read_lock(rw_lock* lock) ASSERT(lock->count >= RW_LOCK_WRITER_COUNT_BASE); // we need to wait - return rw_lock_wait(lock, false); + return rw_lock_wait(lock, false, locker); } @@ -328,7 +337,7 @@ status_t _rw_lock_read_lock_with_timeout(rw_lock* lock, uint32 timeoutFlags, bigtime_t timeout) { - InterruptsSpinLocker locker(gSchedulerLock); + InterruptsSpinLocker locker(lock->lock); // We might be the writer ourselves. if (lock->holder == thread_get_current_thread_id()) { @@ -368,13 +377,16 @@ _rw_lock_read_lock_with_timeout(rw_lock* lock, uint32 timeoutFlags, // block thread_prepare_to_block(waiter.thread, 0, THREAD_BLOCK_TYPE_RW_LOCK, lock); - status_t error = thread_block_with_timeout_locked(timeoutFlags, timeout); + locker.Unlock(); + + status_t error = thread_block_with_timeout(timeoutFlags, timeout); if (error == B_OK || waiter.thread == NULL) { // We were unblocked successfully -- potentially our unblocker overtook // us after we already failed. In either case, we've got the lock, now. return B_OK; } + locker.Lock(); // We failed to get the lock -- dequeue from waiter list. rw_lock_waiter* previous = NULL; rw_lock_waiter* other = lock->waiters; @@ -407,9 +419,9 @@ _rw_lock_read_lock_with_timeout(rw_lock* lock, uint32 timeoutFlags, void -_rw_lock_read_unlock(rw_lock* lock, bool schedulerLocked) +_rw_lock_read_unlock(rw_lock* lock) { - InterruptsSpinLocker locker(gSchedulerLock, false, !schedulerLocked); + InterruptsSpinLocker locker(lock->lock); // If we're still holding the write lock or if there are other readers, // no-one can be woken up. @@ -437,7 +449,7 @@ _rw_lock_read_unlock(rw_lock* lock, bool schedulerLocked) status_t rw_lock_write_lock(rw_lock* lock) { - InterruptsSpinLocker locker(gSchedulerLock); + InterruptsSpinLocker locker(lock->lock); // If we're already the lock holder, we just need to increment the owner // count. @@ -462,7 +474,7 @@ rw_lock_write_lock(rw_lock* lock) if (oldCount < RW_LOCK_WRITER_COUNT_BASE) lock->active_readers = oldCount - lock->pending_readers; - status_t status = rw_lock_wait(lock, true); + status_t status = rw_lock_wait(lock, true, locker); if (status == B_OK) { lock->holder = thread; lock->owner_count = RW_LOCK_WRITER_COUNT_BASE; @@ -473,9 +485,9 @@ rw_lock_write_lock(rw_lock* lock) void -_rw_lock_write_unlock(rw_lock* lock, bool schedulerLocked) +_rw_lock_write_unlock(rw_lock* lock) { - InterruptsSpinLocker locker(gSchedulerLock, false, !schedulerLocked); + InterruptsSpinLocker locker(lock->lock); if (thread_get_current_thread_id() != lock->holder) { panic("rw_lock_write_unlock(): lock %p not write-locked by this thread", @@ -562,6 +574,7 @@ mutex_init(mutex* lock, const char *name) { lock->name = name; lock->waiters = NULL; + B_INITIALIZE_SPINLOCK(&lock->lock); #if KDEBUG lock->holder = -1; #else @@ -580,6 +593,7 @@ mutex_init_etc(mutex* lock, const char *name, uint32 flags) { lock->name = (flags & MUTEX_FLAG_CLONE_NAME) != 0 ? strdup(name) : name; lock->waiters = NULL; + B_INITIALIZE_SPINLOCK(&lock->lock); #if KDEBUG lock->holder = -1; #else @@ -600,15 +614,16 @@ mutex_destroy(mutex* lock) ? (char*)lock->name : NULL; // unblock all waiters - InterruptsSpinLocker locker(gSchedulerLock); + InterruptsSpinLocker locker(lock->lock); #if KDEBUG if (lock->waiters != NULL && thread_get_current_thread_id() != lock->holder) { panic("mutex_destroy(): there are blocking threads, but caller doesn't " "hold the lock (%p)", lock); - if (_mutex_lock(lock, true) != B_OK) + if (_mutex_lock(lock, &locker) != B_OK) return; + locker.Lock(); } #endif @@ -617,7 +632,7 @@ mutex_destroy(mutex* lock) lock->waiters = waiter->next; // unblock thread - thread_unblock_locked(waiter->thread, B_ERROR); + thread_unblock(waiter->thread, B_ERROR); } lock->name = NULL; @@ -628,49 +643,69 @@ mutex_destroy(mutex* lock) } +static inline status_t +mutex_lock_threads_locked(mutex* lock, InterruptsSpinLocker* locker) +{ +#if KDEBUG + return _mutex_lock(lock, locker); +#else + if (atomic_add(&lock->count, -1) < 0) + return _mutex_lock(lock, locker); + return B_OK; +#endif +} + + status_t mutex_switch_lock(mutex* from, mutex* to) { - InterruptsSpinLocker locker(gSchedulerLock); + InterruptsSpinLocker locker(to->lock); #if !KDEBUG if (atomic_add(&from->count, 1) < -1) #endif - _mutex_unlock(from, true); + _mutex_unlock(from); - return mutex_lock_threads_locked(to); + return mutex_lock_threads_locked(to, &locker); } status_t mutex_switch_from_read_lock(rw_lock* from, mutex* to) { - InterruptsSpinLocker locker(gSchedulerLock); + InterruptsSpinLocker locker(to->lock); #if KDEBUG_RW_LOCK_DEBUG - _rw_lock_write_unlock(from, true); + _rw_lock_write_unlock(from); #else int32 oldCount = atomic_add(&from->count, -1); if (oldCount >= RW_LOCK_WRITER_COUNT_BASE) - _rw_lock_read_unlock(from, true); + _rw_lock_read_unlock(from); #endif - return mutex_lock_threads_locked(to); + return mutex_lock_threads_locked(to, &locker); } status_t -_mutex_lock(mutex* lock, bool schedulerLocked) +_mutex_lock(mutex* lock, void* _locker) { #if KDEBUG - if (!gKernelStartup && !schedulerLocked && !are_interrupts_enabled()) { + if (!gKernelStartup && _locker == NULL && !are_interrupts_enabled()) { panic("_mutex_lock(): called with interrupts disabled for lock %p", lock); } #endif - // lock only, if !threadsLocked - InterruptsSpinLocker locker(gSchedulerLock, false, !schedulerLocked); + // lock only, if !lockLocked + InterruptsSpinLocker* locker + = reinterpret_cast(_locker); + + InterruptsSpinLocker lockLocker; + if (locker == NULL) { + lockLocker.SetTo(lock->lock, false); + locker = &lockLocker; + } // Might have been released after we decremented the count, but before // we acquired the spinlock. @@ -704,22 +739,21 @@ _mutex_lock(mutex* lock, bool schedulerLocked) // block thread_prepare_to_block(waiter.thread, 0, THREAD_BLOCK_TYPE_MUTEX, lock); - status_t error = thread_block_locked(waiter.thread); + locker->Unlock(); + status_t error = thread_block(); #if KDEBUG if (error == B_OK) - lock->holder = waiter.thread->id; + atomic_set(&lock->holder, waiter.thread->id); #endif - return error; } void -_mutex_unlock(mutex* lock, bool schedulerLocked) +_mutex_unlock(mutex* lock) { - // lock only, if !threadsLocked - InterruptsSpinLocker locker(gSchedulerLock, false, !schedulerLocked); + InterruptsSpinLocker locker(lock->lock); #if KDEBUG if (thread_get_current_thread_id() != lock->holder) { @@ -741,16 +775,19 @@ _mutex_unlock(mutex* lock, bool schedulerLocked) lock->waiters = waiter->next; if (lock->waiters != NULL) lock->waiters->last = waiter->last; +#if KDEBUG + thread_id unblockedThread = waiter->thread->id; +#endif // unblock thread - thread_unblock_locked(waiter->thread, B_OK); + thread_unblock(waiter->thread, B_OK); #if KDEBUG // Already set the holder to the unblocked thread. Besides that this // actually reflects the current situation, setting it to -1 would // cause a race condition, since another locker could think the lock // is not held by anyone. - lock->holder = waiter->thread->id; + lock->holder = unblockedThread; #endif } else { // We've acquired the spinlock before the locker that is going to wait. @@ -768,7 +805,7 @@ status_t _mutex_trylock(mutex* lock) { #if KDEBUG - InterruptsSpinLocker _(gSchedulerLock); + InterruptsSpinLocker _(lock->lock); if (lock->holder <= 0) { lock->holder = thread_get_current_thread_id(); @@ -789,7 +826,7 @@ _mutex_lock_with_timeout(mutex* lock, uint32 timeoutFlags, bigtime_t timeout) } #endif - InterruptsSpinLocker locker(gSchedulerLock); + InterruptsSpinLocker locker(lock->lock); // Might have been released after we decremented the count, but before // we acquired the spinlock. @@ -823,13 +860,17 @@ _mutex_lock_with_timeout(mutex* lock, uint32 timeoutFlags, bigtime_t timeout) // block thread_prepare_to_block(waiter.thread, 0, THREAD_BLOCK_TYPE_MUTEX, lock); - status_t error = thread_block_with_timeout_locked(timeoutFlags, timeout); + locker.Unlock(); + + status_t error = thread_block_with_timeout(timeoutFlags, timeout); if (error == B_OK) { #if KDEBUG lock->holder = waiter.thread->id; #endif } else { + locker.Lock(); + // If the timeout occurred, we must remove our waiter structure from // the queue. mutex_waiter* previousWaiter = NULL; diff --git a/src/system/kernel/locks/user_mutex.cpp b/src/system/kernel/locks/user_mutex.cpp index d842bfcc41..42e2d933c0 100644 --- a/src/system/kernel/locks/user_mutex.cpp +++ b/src/system/kernel/locks/user_mutex.cpp @@ -99,7 +99,7 @@ remove_user_mutex_entry(UserMutexEntry* entry) static status_t -user_mutex_lock_locked(vint32* mutex, addr_t physicalAddress, const char* name, +user_mutex_lock_locked(int32* mutex, addr_t physicalAddress, const char* name, uint32 flags, bigtime_t timeout, MutexLocker& locker) { // mark the mutex locked + waiting @@ -148,7 +148,7 @@ user_mutex_lock_locked(vint32* mutex, addr_t physicalAddress, const char* name, static void -user_mutex_unlock_locked(vint32* mutex, addr_t physicalAddress, uint32 flags) +user_mutex_unlock_locked(int32* mutex, addr_t physicalAddress, uint32 flags) { if (UserMutexEntry* entry = sUserMutexTable.Lookup(physicalAddress)) { // Someone is waiting -- set the locked flag. It might still be set, diff --git a/src/system/kernel/main.cpp b/src/system/kernel/main.cpp index ef34cfeae4..f71167be9b 100644 --- a/src/system/kernel/main.cpp +++ b/src/system/kernel/main.cpp @@ -76,6 +76,15 @@ static uint32 sCpuRendezvous3; static int32 main2(void *); +static void +non_boot_cpu_init(void* args, int currentCPU) +{ + kernel_args* kernelArgs = (kernel_args*)args; + if (currentCPU != 0) + cpu_init_percpu(kernelArgs, currentCPU); +} + + extern "C" int _start(kernel_args *bootKernelArgs, int currentCPU) { @@ -92,13 +101,13 @@ _start(kernel_args *bootKernelArgs, int currentCPU) smp_set_num_cpus(bootKernelArgs->num_cpus); // wait for all the cpus to get here - smp_cpu_rendezvous(&sCpuRendezvous, currentCPU); + smp_cpu_rendezvous(&sCpuRendezvous); // the passed in kernel args are in a non-allocated range of memory if (currentCPU == 0) memcpy(&sKernelArgs, bootKernelArgs, sizeof(kernel_args)); - smp_cpu_rendezvous(&sCpuRendezvous2, currentCPU); + smp_cpu_rendezvous(&sCpuRendezvous2); // do any pre-booting cpu config cpu_preboot_init_percpu(&sKernelArgs, currentCPU); @@ -150,11 +159,14 @@ _start(kernel_args *bootKernelArgs, int currentCPU) int_init_post_vm(&sKernelArgs); cpu_init_post_vm(&sKernelArgs); commpage_init(); + call_all_cpus_sync(non_boot_cpu_init, &sKernelArgs); + TRACE("init system info\n"); system_info_init(&sKernelArgs); TRACE("init SMP\n"); smp_init(&sKernelArgs); + cpu_build_topology_tree(); TRACE("init timer\n"); timer_init(&sKernelArgs); TRACE("init real time clock\n"); @@ -210,13 +222,13 @@ _start(kernel_args *bootKernelArgs, int currentCPU) TRACE("waking up AP cpus\n"); sCpuRendezvous = sCpuRendezvous2 = 0; smp_wake_up_non_boot_cpus(); - smp_cpu_rendezvous(&sCpuRendezvous, 0); // wait until they're booted + smp_cpu_rendezvous(&sCpuRendezvous); // wait until they're booted // exit the kernel startup phase (mutexes, etc work from now on out) TRACE("exiting kernel startup\n"); gKernelStartup = false; - smp_cpu_rendezvous(&sCpuRendezvous2, 0); + smp_cpu_rendezvous(&sCpuRendezvous2); // release the AP cpus to go enter the scheduler TRACE("starting scheduler on cpu 0 and enabling interrupts\n"); @@ -230,12 +242,11 @@ _start(kernel_args *bootKernelArgs, int currentCPU) arch_cpu_global_TLB_invalidate(); // this is run for each non boot processor after they've been set loose - cpu_init_percpu(&sKernelArgs, currentCPU); smp_per_cpu_init(&sKernelArgs, currentCPU); // wait for all other AP cpus to get to this point - smp_cpu_rendezvous(&sCpuRendezvous, currentCPU); - smp_cpu_rendezvous(&sCpuRendezvous2, currentCPU); + smp_cpu_rendezvous(&sCpuRendezvous); + smp_cpu_rendezvous(&sCpuRendezvous2); // welcome to the machine scheduler_start(); @@ -252,7 +263,7 @@ _start(kernel_args *bootKernelArgs, int currentCPU) #endif for (;;) - arch_cpu_idle(); + cpu_idle(); return 0; } diff --git a/src/system/kernel/port.cpp b/src/system/kernel/port.cpp index 249df45408..e0d584aa55 100644 --- a/src/system/kernel/port.cpp +++ b/src/system/kernel/port.cpp @@ -118,7 +118,7 @@ struct Port : public KernelReferenceable { size_t name_hash; int32 capacity; mutex lock; - vint32 state; + int32 state; uint32 read_count; int32 write_count; ConditionVariable read_condition; @@ -417,13 +417,13 @@ static const size_t kBufferGrowRate = kInitialPortBufferSize; #define PORT_MAX_MESSAGE_SIZE (256 * 1024) static int32 sMaxPorts = 4096; -static vint32 sUsedPorts; +static int32 sUsedPorts; static PortHashTable sPorts; static PortNameHashTable sPortsByName; static ConditionVariable sNoSpaceCondition; -static vint32 sTotalSpaceCommited; -static vint32 sWaitingForSpace; +static int32 sTotalSpaceCommited; +static int32 sWaitingForSpace; static port_id sNextPortID = 1; static bool sPortsActive = false; static rw_lock sPortsLock = RW_LOCK_INITIALIZER("ports list"); @@ -772,8 +772,8 @@ uninit_port(Port* port) // Release the threads that were blocking on this port. // read_port() will see the B_BAD_PORT_ID return value, and act accordingly - port->read_condition.NotifyAll(false, B_BAD_PORT_ID); - port->write_condition.NotifyAll(false, B_BAD_PORT_ID); + port->read_condition.NotifyAll(B_BAD_PORT_ID); + port->write_condition.NotifyAll(B_BAD_PORT_ID); sNotificationService.Notify(PORT_REMOVED, port->id); } @@ -1055,8 +1055,8 @@ close_port(port_id id) notify_port_select_events(portRef, B_EVENT_INVALID); portRef->select_infos = NULL; - portRef->read_condition.NotifyAll(false, B_BAD_PORT_ID); - portRef->write_condition.NotifyAll(false, B_BAD_PORT_ID); + portRef->read_condition.NotifyAll(B_BAD_PORT_ID); + portRef->write_condition.NotifyAll(B_BAD_PORT_ID); return B_OK; } diff --git a/src/system/kernel/posix/realtime_sem.cpp b/src/system/kernel/posix/realtime_sem.cpp index 2e25c53569..7c51e80666 100644 --- a/src/system/kernel/posix/realtime_sem.cpp +++ b/src/system/kernel/posix/realtime_sem.cpp @@ -141,7 +141,7 @@ public: private: char* fName; - vint32 fRefCount; + int32 fRefCount; uid_t fUID; gid_t fGID; mode_t fPermissions; diff --git a/src/system/kernel/posix/xsi_message_queue.cpp b/src/system/kernel/posix/xsi_message_queue.cpp index 278c241f67..00046cb906 100644 --- a/src/system/kernel/posix/xsi_message_queue.cpp +++ b/src/system/kernel/posix/xsi_message_queue.cpp @@ -126,12 +126,11 @@ public: // Unlock the queue before blocking queueLocker->Unlock(); - InterruptsSpinLocker schedulerLocker(gSchedulerLock); // TODO: We've got a serious race condition: If BlockAndUnlock() returned due to // interruption, we will still be queued. A WakeUpThread() at this point will // call thread_unblock() and might thus screw with our trying to re-lock the // mutex. - return thread_block_locked(thread); + return thread_block(); } void DoIpcSet(struct msqid_ds *result) @@ -246,8 +245,6 @@ public: void WakeUpThread(bool waitForMessage) { - InterruptsSpinLocker schedulerLocker(gSchedulerLock); - if (waitForMessage) { // Wake up all waiting thread for a message // TODO: this can cause starvation for any @@ -255,14 +252,14 @@ public: while (queued_thread *entry = fWaitingToReceive.RemoveHead()) { entry->queued = false; fThreadsWaitingToReceive--; - thread_unblock_locked(entry->thread, 0); + thread_unblock(entry->thread, 0); } } else { // Wake up only one thread waiting to send if (queued_thread *entry = fWaitingToSend.RemoveHead()) { entry->queued = false; fThreadsWaitingToSend--; - thread_unblock_locked(entry->thread, 0); + thread_unblock(entry->thread, 0); } } } @@ -387,8 +384,8 @@ static mutex sIpcLock; static mutex sXsiMessageQueueLock; static uint32 sGlobalSequenceNumber = 1; -static vint32 sXsiMessageCount = 0; -static vint32 sXsiMessageQueueCount = 0; +static int32 sXsiMessageCount = 0; +static int32 sXsiMessageQueueCount = 0; // #pragma mark - @@ -400,15 +397,13 @@ XsiMessageQueue::~XsiMessageQueue() // Wake up any threads still waiting if (fThreadsWaitingToSend || fThreadsWaitingToReceive) { - InterruptsSpinLocker schedulerLocker(gSchedulerLock); - while (queued_thread *entry = fWaitingToReceive.RemoveHead()) { entry->queued = false; - thread_unblock_locked(entry->thread, EIDRM); + thread_unblock(entry->thread, EIDRM); } while (queued_thread *entry = fWaitingToSend.RemoveHead()) { entry->queued = false; - thread_unblock_locked(entry->thread, EIDRM); + thread_unblock(entry->thread, EIDRM); } } @@ -694,7 +689,7 @@ _user_xsi_msgget(key_t key, int flags) if (create) { // Create a new message queue for this key - if (sXsiMessageQueueCount >= MAX_XSI_MESSAGE_QUEUE) { + if (atomic_get(&sXsiMessageQueueCount) >= MAX_XSI_MESSAGE_QUEUE) { TRACE_ERROR(("xsi_msgget: reached limit of maximun number of " "message queues\n")); return ENOSPC; diff --git a/src/system/kernel/posix/xsi_semaphore.cpp b/src/system/kernel/posix/xsi_semaphore.cpp index 212ee1b592..5a48f9d28d 100644 --- a/src/system/kernel/posix/xsi_semaphore.cpp +++ b/src/system/kernel/posix/xsi_semaphore.cpp @@ -101,15 +101,13 @@ public: { // For some reason the semaphore is getting destroyed. // Wake up any remaing awaiting threads - InterruptsSpinLocker schedulerLocker(gSchedulerLock); - while (queued_thread *entry = fWaitingToIncreaseQueue.RemoveHead()) { entry->queued = false; - thread_unblock_locked(entry->thread, EIDRM); + thread_unblock(entry->thread, EIDRM); } while (queued_thread *entry = fWaitingToBeZeroQueue.RemoveHead()) { entry->queued = false; - thread_unblock_locked(entry->thread, EIDRM); + thread_unblock(entry->thread, EIDRM); } // No need to remove any sem_undo request still // hanging. When the process exit and doesn't found @@ -144,12 +142,11 @@ public: // Unlock the set before blocking setLocker->Unlock(); - InterruptsSpinLocker schedulerLocker(gSchedulerLock); // TODO: We've got a serious race condition: If BlockAndUnlock() returned due to // interruption, we will still be queued. A WakeUpThread() at this point will // call thread_unblock() and might thus screw with our trying to re-lock the // mutex. - return thread_block_locked(thread); + return thread_block(); } void Deque(queued_thread *queueEntry, bool waitForZero) @@ -218,20 +215,19 @@ public: void WakeUpThread(bool waitingForZero) { - InterruptsSpinLocker schedulerLocker(gSchedulerLock); if (waitingForZero) { // Wake up all threads waiting on zero while (queued_thread *entry = fWaitingToBeZeroQueue.RemoveHead()) { entry->queued = false; fThreadsWaitingToBeZero--; - thread_unblock_locked(entry->thread, 0); + thread_unblock(entry->thread, 0); } } else { // Wake up all threads even though they might go back to sleep while (queued_thread *entry = fWaitingToIncreaseQueue.RemoveHead()) { entry->queued = false; fThreadsWaitingToIncrease--; - thread_unblock_locked(entry->thread, 0); + thread_unblock(entry->thread, 0); } } } @@ -634,8 +630,8 @@ static mutex sIpcLock; static mutex sXsiSemaphoreSetLock; static uint32 sGlobalSequenceNumber = 1; -static vint32 sXsiSemaphoreCount = 0; -static vint32 sXsiSemaphoreSetCount = 0; +static int32 sXsiSemaphoreCount = 0; +static int32 sXsiSemaphoreSetCount = 0; // #pragma mark - diff --git a/src/system/kernel/scheduler/RunQueue.h b/src/system/kernel/scheduler/RunQueue.h new file mode 100644 index 0000000000..aae6482195 --- /dev/null +++ b/src/system/kernel/scheduler/RunQueue.h @@ -0,0 +1,397 @@ +/* + * Copyright 2013 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ +#ifndef RUN_QUEUE_H +#define RUN_QUEUE_H + + +#include + +#include "scheduler_profiler.h" + + +template +struct RunQueueLink { + RunQueueLink(); + + unsigned int fPriority; + Element* fPrevious; + Element* fNext; +}; + +template +class RunQueueLinkImpl { +public: + inline RunQueueLink* GetRunQueueLink(); + +private: + RunQueueLink fRunQueueLink; +}; + +template +class RunQueueStandardGetLink { +private: + typedef RunQueueLink Link; + +public: + inline Link* operator()(Element* element) const; +}; + +template Element::*LinkMember> +class RunQueueMemberGetLink { +private: + typedef RunQueueLink Link; + +public: + inline Link* operator()(Element* element) const; +}; + +#define RUN_QUEUE_TEMPLATE_LIST \ + template +#define RUN_QUEUE_CLASS_NAME RunQueue + +template > +class RunQueue { +public: + class ConstIterator { + public: + ConstIterator(); + ConstIterator(const RunQueue* list); + + inline ConstIterator& operator=(const ConstIterator& other); + + bool HasNext() const; + Element* Next(); + + void Rewind(); + + private: + inline void _FindNextPriority(); + + const RUN_QUEUE_CLASS_NAME* fList; + unsigned int fPriority; + Element* fNext; + + static GetLink sGetLink; + }; + + RunQueue(); + + inline status_t GetInitStatus(); + + inline Element* PeekMaximum() const; + + inline void PushFront(Element* element, unsigned int priority); + inline void PushBack(Element* elementt, unsigned int priority); + + inline void Remove(Element* element); + + inline Element* GetHead(unsigned int priority) const; + + inline ConstIterator GetConstIterator() const; + +private: + struct PriorityEntry : public HeapLinkImpl + { + }; + + typedef Heap > + PriorityHeap; + + status_t fInitStatus; + + PriorityEntry fPriorityEntries[MaxPriority + 1]; + PriorityHeap fPriorityHeap; + + Element* fHeads[MaxPriority + 1]; + Element* fTails[MaxPriority + 1]; + + static GetLink sGetLink; +}; + + +template +RunQueueLink::RunQueueLink() + : + fPrevious(NULL), + fNext(NULL) +{ +} + + +template +RunQueueLink* +RunQueueLinkImpl::GetRunQueueLink() +{ + return &fRunQueueLink; +} + + +template +RunQueueLink* +RunQueueStandardGetLink::operator()(Element* element) const +{ + return element->GetRunQueueLink(); +} + + +template Element::*LinkMember> +RunQueueLink* +RunQueueMemberGetLink::operator()(Element* element) const +{ + return &(element->*LinkMember); +} + + +RUN_QUEUE_TEMPLATE_LIST +RUN_QUEUE_CLASS_NAME::ConstIterator::ConstIterator() + : + fList(NULL) +{ +} + + +RUN_QUEUE_TEMPLATE_LIST +RUN_QUEUE_CLASS_NAME::ConstIterator::ConstIterator(const RunQueue* list) + : + fList(list) +{ + Rewind(); +} + + +RUN_QUEUE_TEMPLATE_LIST +typename RUN_QUEUE_CLASS_NAME::ConstIterator& +RUN_QUEUE_CLASS_NAME::ConstIterator::operator=(const ConstIterator& other) +{ + fList = other.fList; + fPriority = other.fPriority; + fNext = other.fNext; + + return *this; +} + + +RUN_QUEUE_TEMPLATE_LIST +bool +RUN_QUEUE_CLASS_NAME::ConstIterator::HasNext() const +{ + return fNext != NULL; +} + + +RUN_QUEUE_TEMPLATE_LIST +Element* +RUN_QUEUE_CLASS_NAME::ConstIterator::Next() +{ + ASSERT(HasNext()); + + Element* current = fNext; + RunQueueLink* link = sGetLink(fNext); + + fNext = link->fNext; + if (fNext == NULL) + _FindNextPriority(); + + return current; +} + + +RUN_QUEUE_TEMPLATE_LIST +void +RUN_QUEUE_CLASS_NAME::ConstIterator::Rewind() +{ + ASSERT(fList != NULL); + + fPriority = MaxPriority; + fNext = fList->GetHead(fPriority); + if (fNext == NULL) + _FindNextPriority(); +} + + +RUN_QUEUE_TEMPLATE_LIST +void +RUN_QUEUE_CLASS_NAME::ConstIterator::_FindNextPriority() +{ + ASSERT(fList != NULL); + + while (fPriority-- > 0) { + fNext = fList->GetHead(fPriority); + if (fNext != NULL) + break; + } +} + + +RUN_QUEUE_TEMPLATE_LIST +RUN_QUEUE_CLASS_NAME::RunQueue() + : + fInitStatus(B_OK), + fPriorityHeap(MaxPriority + 1) +{ + memset(fHeads, 0, sizeof(fHeads)); + memset(fTails, 0, sizeof(fTails)); +} + + +RUN_QUEUE_TEMPLATE_LIST +status_t +RUN_QUEUE_CLASS_NAME::GetInitStatus() +{ + return fInitStatus; +} + + +RUN_QUEUE_TEMPLATE_LIST +Element* +RUN_QUEUE_CLASS_NAME::PeekMaximum() const +{ + SCHEDULER_ENTER_FUNCTION(); + + PriorityEntry* maxPriority = fPriorityHeap.PeekRoot(); + if (maxPriority == NULL) + return NULL; + unsigned int priority = PriorityHeap::GetKey(maxPriority); + + ASSERT(priority <= MaxPriority); + ASSERT(fHeads[priority] != NULL); + + Element* element = fHeads[priority]; + + ASSERT(sGetLink(element)->fPriority == priority); + ASSERT(fTails[priority] != NULL); + ASSERT(sGetLink(element)->fPrevious == NULL); + + return element; +} + + +RUN_QUEUE_TEMPLATE_LIST +void +RUN_QUEUE_CLASS_NAME::PushFront(Element* element, + unsigned int priority) +{ + SCHEDULER_ENTER_FUNCTION(); + + ASSERT(priority <= MaxPriority); + + RunQueueLink* elementLink = sGetLink(element); + + ASSERT(elementLink->fPrevious == NULL); + ASSERT(elementLink->fNext == NULL); + + ASSERT((fHeads[priority] == NULL && fTails[priority] == NULL) + || (fHeads[priority] != NULL && fTails[priority] != NULL)); + + elementLink->fPriority = priority; + elementLink->fNext = fHeads[priority]; + if (fHeads[priority] != NULL) + sGetLink(fHeads[priority])->fPrevious = element; + else { + fTails[priority] = element; + fPriorityHeap.Insert(&fPriorityEntries[priority], priority); + } + fHeads[priority] = element; +} + + +RUN_QUEUE_TEMPLATE_LIST +void +RUN_QUEUE_CLASS_NAME::PushBack(Element* element, + unsigned int priority) +{ + SCHEDULER_ENTER_FUNCTION(); + + ASSERT(priority <= MaxPriority); + + RunQueueLink* elementLink = sGetLink(element); + + ASSERT(elementLink->fPrevious == NULL); + ASSERT(elementLink->fNext == NULL); + + ASSERT((fHeads[priority] == NULL && fTails[priority] == NULL) + || (fHeads[priority] != NULL && fTails[priority] != NULL)); + + elementLink->fPriority = priority; + elementLink->fPrevious = fTails[priority]; + if (fTails[priority] != NULL) + sGetLink(fTails[priority])->fNext = element; + else { + fHeads[priority] = element; + fPriorityHeap.Insert(&fPriorityEntries[priority], priority); + } + fTails[priority] = element; +} + + +RUN_QUEUE_TEMPLATE_LIST +void +RUN_QUEUE_CLASS_NAME::Remove(Element* element) +{ + SCHEDULER_ENTER_FUNCTION(); + + RunQueueLink* elementLink = sGetLink(element); + unsigned int priority = elementLink->fPriority; + + ASSERT(elementLink->fPrevious != NULL || fHeads[priority] == element); + ASSERT(elementLink->fNext != NULL || fTails[priority] == element); + + if (elementLink->fPrevious != NULL) + sGetLink(elementLink->fPrevious)->fNext = elementLink->fNext; + else + fHeads[priority] = elementLink->fNext; + if (elementLink->fNext != NULL) + sGetLink(elementLink->fNext)->fPrevious = elementLink->fPrevious; + else + fTails[priority] = elementLink->fPrevious; + + ASSERT((fHeads[priority] == NULL && fTails[priority] == NULL) + || (fHeads[priority] != NULL && fTails[priority] != NULL)); + + if (fHeads[priority] == NULL) { + fPriorityHeap.ModifyKey(&fPriorityEntries[priority], MaxPriority + 1); + ASSERT(fPriorityHeap.PeekRoot() == &fPriorityEntries[priority]); + fPriorityHeap.RemoveRoot(); + } + + elementLink->fPrevious = NULL; + elementLink->fNext = NULL; +} + + +RUN_QUEUE_TEMPLATE_LIST +Element* +RUN_QUEUE_CLASS_NAME::GetHead(unsigned int priority) const +{ + SCHEDULER_ENTER_FUNCTION(); + + ASSERT(priority <= MaxPriority); + return fHeads[priority]; +} + + +RUN_QUEUE_TEMPLATE_LIST +typename RUN_QUEUE_CLASS_NAME::ConstIterator +RUN_QUEUE_CLASS_NAME::GetConstIterator() const +{ + return ConstIterator(this); +} + + +RUN_QUEUE_TEMPLATE_LIST +GetLink RUN_QUEUE_CLASS_NAME::sGetLink; + +RUN_QUEUE_TEMPLATE_LIST +GetLink RUN_QUEUE_CLASS_NAME::ConstIterator::sGetLink; + + +#endif // RUN_QUEUE_H + diff --git a/src/system/kernel/scheduler/low_latency.cpp b/src/system/kernel/scheduler/low_latency.cpp new file mode 100644 index 0000000000..911353f2a1 --- /dev/null +++ b/src/system/kernel/scheduler/low_latency.cpp @@ -0,0 +1,180 @@ +/* + * Copyright 2013, Paweł Dziepak, pdziepak@quarnos.org. + * Distributed under the terms of the MIT License. + */ + + +#include + +#include "scheduler_common.h" +#include "scheduler_cpu.h" +#include "scheduler_modes.h" +#include "scheduler_profiler.h" +#include "scheduler_thread.h" + + +using namespace Scheduler; + + +const bigtime_t kCacheExpire = 100000; + + +static void +switch_to_mode() +{ +} + + +static void +set_cpu_enabled(int32 /* cpu */, bool /* enabled */) +{ +} + + +static bool +has_cache_expired(const ThreadData* threadData) +{ + SCHEDULER_ENTER_FUNCTION(); + if (threadData->WentSleepActive() == 0) + return false; + CoreEntry* core = threadData->Core(); + bigtime_t activeTime = core->GetActiveTime(); + return activeTime - threadData->WentSleepActive() > kCacheExpire; +} + + +static CoreEntry* +choose_core(const ThreadData* /* threadData */) +{ + SCHEDULER_ENTER_FUNCTION(); + + // wake new package + PackageEntry* package = gIdlePackageList.Last(); + if (package == NULL) { + // wake new core + package = PackageEntry::GetMostIdlePackage(); + } + + CoreEntry* core = NULL; + if (package != NULL) + core = package->GetIdleCore(); + + if (core == NULL) { + ReadSpinLocker coreLocker(gCoreHeapsLock); + // no idle cores, use least occupied core + core = gCoreLoadHeap.PeekMinimum(); + if (core == NULL) + core = gCoreHighLoadHeap.PeekMinimum(); + } + + ASSERT(core != NULL); + return core; +} + + +static bool +should_rebalance(const ThreadData* threadData) +{ + SCHEDULER_ENTER_FUNCTION(); + + int32 coreLoad = threadData->Core()->GetLoad(); + int32 threadLoad = threadData->GetLoad() / threadData->Core()->CPUCount(); + + // If the thread produces more than 50% of the load, leave it here. In + // such situation it is better to move other threads away. + if (threadLoad >= coreLoad / 2) + return false; + + int32 coreNewLoad = coreLoad - threadLoad; + + // If there is high load on this core but this thread does not contribute + // significantly consider giving it to someone less busy. + if (coreLoad > kHighLoad) { + CoreEntry* other = gCoreLoadHeap.PeekMinimum(); + if (other != NULL) { + int32 otherNewLoad = other->GetLoad() + threadLoad; + if (coreNewLoad - otherNewLoad >= kLoadDifference) + return true; + } + } + + // No cpu bound threads - the situation is quite good. Make sure it + // won't get much worse... + ReadSpinLocker coreLocker(gCoreHeapsLock); + CoreEntry* other = gCoreLoadHeap.PeekMinimum(); + if (other == NULL) + other = gCoreHighLoadHeap.PeekMinimum(); + coreLocker.Unlock(); + + if (other->GetLoad() == 0 && coreNewLoad != 0) + return true; + + int32 otherNewLoad = other->GetLoad() + threadLoad; + return coreNewLoad - otherNewLoad >= kLoadDifference * 2; +} + + +static void +rebalance_irqs(bool idle) +{ + SCHEDULER_ENTER_FUNCTION(); + + if (idle) + return; + + cpu_ent* cpu = get_cpu_struct(); + SpinLocker locker(cpu->irqs_lock); + + irq_assignment* chosen = NULL; + irq_assignment* irq = (irq_assignment*)list_get_first_item(&cpu->irqs); + + int32 totalLoad = 0; + while (irq != NULL) { + if (chosen == NULL || chosen->load < irq->load) + chosen = irq; + totalLoad += irq->load; + irq = (irq_assignment*)list_get_next_item(&cpu->irqs, irq); + } + + locker.Unlock(); + + if (chosen == NULL || totalLoad < kLowLoad) + return; + + ReadSpinLocker coreLocker(gCoreHeapsLock); + CoreEntry* other = gCoreLoadHeap.PeekMinimum(); + if (other == NULL) + other = gCoreHighLoadHeap.PeekMinimum(); + coreLocker.Unlock(); + + int32 newCPU = other->CPUHeap()->PeekRoot()->ID(); + + ASSERT(other != NULL); + + CoreEntry* core = CoreEntry::GetCore(cpu->cpu_num); + if (other == core) + return; + if (other->GetLoad() + kLoadDifference >= core->GetLoad()) + return; + + assign_io_interrupt_to_cpu(chosen->irq, newCPU); +} + + +scheduler_mode_operations gSchedulerLowLatencyMode = { + "low latency", + + 1000, + 100, + { 2, 5 }, + + 5000, + + switch_to_mode, + set_cpu_enabled, + has_cache_expired, + choose_core, + should_rebalance, + rebalance_irqs, +}; + diff --git a/src/system/kernel/scheduler/power_saving.cpp b/src/system/kernel/scheduler/power_saving.cpp new file mode 100644 index 0000000000..54c2db1795 --- /dev/null +++ b/src/system/kernel/scheduler/power_saving.cpp @@ -0,0 +1,252 @@ +/* + * Copyright 2013, Paweł Dziepak, pdziepak@quarnos.org. + * Distributed under the terms of the MIT License. + */ + + +#include +#include + +#include "scheduler_common.h" +#include "scheduler_cpu.h" +#include "scheduler_modes.h" +#include "scheduler_profiler.h" +#include "scheduler_thread.h" + + +using namespace Scheduler; + + +const bigtime_t kCacheExpire = 100000; + +static CoreEntry* sSmallTaskCore; + + +static void +switch_to_mode() +{ + sSmallTaskCore = NULL; +} + + +static void +set_cpu_enabled(int32 cpu, bool enabled) +{ + if (!enabled) + sSmallTaskCore = NULL; +} + + +static bool +has_cache_expired(const ThreadData* threadData) +{ + SCHEDULER_ENTER_FUNCTION(); + if (threadData->WentSleep() == 0) + return false; + return system_time() - threadData->WentSleep() > kCacheExpire; +} + + +static CoreEntry* +choose_small_task_core() +{ + SCHEDULER_ENTER_FUNCTION(); + + CoreEntry* core = gCoreLoadHeap.PeekMaximum(); + if (core == NULL) + return sSmallTaskCore; + + CoreEntry* smallTaskCore + = atomic_pointer_test_and_set(&sSmallTaskCore, core, (CoreEntry*)NULL); + if (smallTaskCore == NULL) + return core; + return smallTaskCore; +} + + +static CoreEntry* +choose_idle_core() +{ + SCHEDULER_ENTER_FUNCTION(); + + PackageEntry* package = PackageEntry::GetLeastIdlePackage(); + + if (package == NULL) + package = gIdlePackageList.Last(); + + if (package != NULL) + return package->GetIdleCore(); + + return NULL; +} + + +static CoreEntry* +choose_core(const ThreadData* threadData) +{ + SCHEDULER_ENTER_FUNCTION(); + + CoreEntry* core = NULL; + + // try to pack all threads on one core + core = choose_small_task_core(); + + if (core == NULL || core->GetLoad() + threadData->GetLoad() >= kHighLoad) { + ReadSpinLocker coreLocker(gCoreHeapsLock); + + // run immediately on already woken core + core = gCoreLoadHeap.PeekMinimum(); + if (core == NULL) { + coreLocker.Unlock(); + + core = choose_idle_core(); + + if (core == NULL) { + coreLocker.Lock(); + core = gCoreHighLoadHeap.PeekMinimum(); + } + } + } + + ASSERT(core != NULL); + return core; +} + + +static bool +should_rebalance(const ThreadData* threadData) +{ + SCHEDULER_ENTER_FUNCTION(); + + ASSERT(!gSingleCore); + + CoreEntry* core = threadData->Core(); + + int32 coreLoad = core->GetLoad(); + int32 threadLoad = threadData->GetLoad() / core->CPUCount(); + if (coreLoad > kHighLoad) { + if (sSmallTaskCore == core) { + sSmallTaskCore = NULL; + choose_small_task_core(); + + if (threadLoad > coreLoad / 3) + return false; + return coreLoad > kVeryHighLoad; + } + + if (threadLoad >= coreLoad / 2) + return false; + + CoreEntry* other = gCoreLoadHeap.PeekMaximum(); + if (other == NULL) + other = gCoreHighLoadHeap.PeekMinimum(); + ASSERT(other != NULL); + + int32 coreNewLoad = coreLoad - threadLoad; + int32 otherNewLoad = other->GetLoad() + threadLoad; + return coreNewLoad - otherNewLoad >= kLoadDifference / 2; + } + + if (coreLoad >= kMediumLoad) + return false; + + CoreEntry* smallTaskCore = choose_small_task_core(); + if (smallTaskCore == NULL) + return false; + return smallTaskCore != core + && smallTaskCore->GetLoad() + threadLoad < kHighLoad; +} + + +static inline void +pack_irqs() +{ + SCHEDULER_ENTER_FUNCTION(); + + CoreEntry* smallTaskCore = atomic_pointer_get(&sSmallTaskCore); + if (smallTaskCore == NULL) + return; + + cpu_ent* cpu = get_cpu_struct(); + if (smallTaskCore == CoreEntry::GetCore(cpu->cpu_num)) + return; + + SpinLocker locker(cpu->irqs_lock); + while (list_get_first_item(&cpu->irqs) != NULL) { + irq_assignment* irq = (irq_assignment*)list_get_first_item(&cpu->irqs); + locker.Unlock(); + + int32 newCPU = smallTaskCore->CPUHeap()->PeekRoot()->ID(); + + if (newCPU != cpu->cpu_num) + assign_io_interrupt_to_cpu(irq->irq, newCPU); + + locker.Lock(); + } +} + + +static void +rebalance_irqs(bool idle) +{ + SCHEDULER_ENTER_FUNCTION(); + + if (idle && sSmallTaskCore != NULL) { + pack_irqs(); + return; + } + + if (idle || sSmallTaskCore != NULL) + return; + + cpu_ent* cpu = get_cpu_struct(); + SpinLocker locker(cpu->irqs_lock); + + irq_assignment* chosen = NULL; + irq_assignment* irq = (irq_assignment*)list_get_first_item(&cpu->irqs); + + while (irq != NULL) { + if (chosen == NULL || chosen->load < irq->load) + chosen = irq; + irq = (irq_assignment*)list_get_next_item(&cpu->irqs, irq); + } + + locker.Unlock(); + + if (chosen == NULL || chosen->load < kLowLoad) + return; + + ReadSpinLocker coreLocker(gCoreHeapsLock); + CoreEntry* other = gCoreLoadHeap.PeekMinimum(); + coreLocker.Unlock(); + if (other == NULL) + return; + int32 newCPU = other->CPUHeap()->PeekRoot()->ID(); + + CoreEntry* core = CoreEntry::GetCore(smp_get_current_cpu()); + if (other == core) + return; + if (other->GetLoad() + kLoadDifference >= core->GetLoad()) + return; + + assign_io_interrupt_to_cpu(chosen->irq, newCPU); +} + + +scheduler_mode_operations gSchedulerPowerSavingMode = { + "power saving", + + 2000, + 500, + { 3, 10 }, + + 20000, + + switch_to_mode, + set_cpu_enabled, + has_cache_expired, + choose_core, + should_rebalance, + rebalance_irqs, +}; + diff --git a/src/system/kernel/scheduler/scheduler.cpp b/src/system/kernel/scheduler/scheduler.cpp index e4848d1d48..6437cb0d32 100644 --- a/src/system/kernel/scheduler/scheduler.cpp +++ b/src/system/kernel/scheduler/scheduler.cpp @@ -1,33 +1,799 @@ /* + * Copyright 2013-2014, Paweł Dziepak, pdziepak@quarnos.org. + * Copyright 2009, Rene Gollent, rene@gollent.com. * Copyright 2008-2011, Ingo Weinhold, ingo_weinhold@gmx.de. - * Copyright 2010, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2002-2010, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2002, Angelo Mottola, a.mottola@libero.it. * Distributed under the terms of the MIT License. + * + * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. + * Distributed under the terms of the NewOS License. */ +/*! The thread scheduler */ + + +#include + +#include +#include +#include +#include +#include #include #include +#include +#include #include +#include +#include -#include "scheduler_affine.h" -#include "scheduler_simple.h" -#include "scheduler_simple_smp.h" +#include "scheduler_common.h" +#include "scheduler_cpu.h" +#include "scheduler_locking.h" +#include "scheduler_modes.h" +#include "scheduler_profiler.h" +#include "scheduler_thread.h" #include "scheduler_tracing.h" -struct scheduler_ops* gScheduler; -spinlock gSchedulerLock = B_SPINLOCK_INITIALIZER; -SchedulerListenerList gSchedulerListeners; +namespace Scheduler { -static void (*sRescheduleFunction)(void); + +class ThreadEnqueuer : public ThreadProcessing { +public: + void operator()(ThreadData* thread); +}; + +scheduler_mode gCurrentModeID; +scheduler_mode_operations* gCurrentMode; + +bool gSingleCore; +bool gTrackCoreLoad; +bool gTrackCPULoad; + +} // namespace Scheduler + +using namespace Scheduler; + + +static bool sSchedulerEnabled; + +SchedulerListenerList gSchedulerListeners; +spinlock gSchedulerListenersLock = B_SPINLOCK_INITIALIZER; + +static scheduler_mode_operations* sSchedulerModes[] = { + &gSchedulerLowLatencyMode, + &gSchedulerPowerSavingMode, +}; + +// Since CPU IDs used internally by the kernel bear no relation to the actual +// CPU topology the following arrays are used to efficiently get the core +// and the package that CPU in question belongs to. +static int32* sCPUToCore; +static int32* sCPUToPackage; + + +static void enqueue(Thread* thread, bool newOne); + + +void +ThreadEnqueuer::operator()(ThreadData* thread) +{ + enqueue(thread->GetThread(), false); +} + + +void +scheduler_dump_thread_data(Thread* thread) +{ + thread->scheduler_data->Dump(); +} static void -scheduler_reschedule_no_op(void) +enqueue(Thread* thread, bool newOne) { - Thread* thread = thread_get_current_thread(); - if (thread != NULL && thread->next_state != B_THREAD_READY) - panic("scheduler_reschedule_no_op() called in non-ready thread"); + SCHEDULER_ENTER_FUNCTION(); + + ThreadData* threadData = thread->scheduler_data; + + int32 threadPriority = threadData->GetEffectivePriority(); + T(EnqueueThread(thread, threadPriority)); + + CPUEntry* targetCPU = NULL; + CoreEntry* targetCore = NULL; + if (thread->pinned_to_cpu > 0) { + ASSERT(thread->previous_cpu != NULL); + targetCPU = &gCPUEntries[thread->previous_cpu->cpu_num]; + } else if (gSingleCore) + targetCore = &gCoreEntries[0]; + else if (threadData->Core() != NULL + && (!newOne || !threadData->HasCacheExpired()) + && !threadData->ShouldRebalance()) { + targetCore = threadData->Core(); + } + + bool rescheduleNeeded = threadData->ChooseCoreAndCPU(targetCore, targetCPU); + + TRACE("enqueueing thread %ld with priority %ld on CPU %ld (core %ld)\n", + thread->id, threadPriority, targetCPU->fCPUNumber, targetCore->fCoreID); + + threadData->Enqueue(); + + // notify listeners + NotifySchedulerListeners(&SchedulerListener::ThreadEnqueuedInRunQueue, + thread); + + int32 heapPriority = CPUPriorityHeap::GetKey(targetCPU); + if (threadPriority > heapPriority + || (threadPriority == heapPriority && rescheduleNeeded)) { + + if (targetCPU->ID() == smp_get_current_cpu()) + gCPU[targetCPU->ID()].invoke_scheduler = true; + else { + smp_send_ici(targetCPU->ID(), SMP_MSG_RESCHEDULE, 0, 0, 0, + NULL, SMP_MSG_FLAG_ASYNC); + } + } +} + + +/*! Enqueues the thread into the run queue. + Note: thread lock must be held when entering this function +*/ +void +scheduler_enqueue_in_run_queue(Thread *thread) +{ + ASSERT(!are_interrupts_enabled()); + SCHEDULER_ENTER_FUNCTION(); + + SchedulerModeLocker _; + + TRACE("enqueueing new thread %ld with static priority %ld\n", thread->id, + thread->priority); + + ThreadData* threadData = thread->scheduler_data; + + if (threadData->ShouldCancelPenalty()) + threadData->CancelPenalty(); + + enqueue(thread, true); +} + + +/*! Sets the priority of a thread. +*/ +int32 +scheduler_set_thread_priority(Thread *thread, int32 priority) +{ + ASSERT(are_interrupts_enabled()); + + InterruptsSpinLocker _(thread->scheduler_lock); + SchedulerModeLocker modeLocker; + + SCHEDULER_ENTER_FUNCTION(); + + ThreadData* threadData = thread->scheduler_data; + int32 oldPriority = thread->priority; + + TRACE("changing thread %ld priority to %ld (old: %ld, effective: %ld)\n", + thread->id, priority, oldPriority, threadData->GetEffectivePriority()); + + threadData->CancelPenalty(); + + if (priority == thread->priority) + return thread->priority; + thread->priority = priority; + + if (thread->state != B_THREAD_READY) { + if (thread->state == B_THREAD_RUNNING) { + ASSERT(threadData->Core() != NULL); + + ASSERT(thread->cpu != NULL); + CPUEntry* cpu = &gCPUEntries[thread->cpu->cpu_num]; + + CoreCPUHeapLocker _(threadData->Core()); + cpu->UpdatePriority(priority); + } + + return oldPriority; + } + + // The thread is in the run queue. We need to remove it and re-insert it at + // a new position. + + T(RemoveThread(thread)); + + // notify listeners + NotifySchedulerListeners(&SchedulerListener::ThreadRemovedFromRunQueue, + thread); + + if (threadData->Dequeue()) + enqueue(thread, true); + + return oldPriority; +} + + +static inline void +reschedule_needed() +{ + // This function is called as a result of either the timer event set by the + // scheduler or an incoming ICI. Make sure the reschedule() is invoked. + get_cpu_struct()->invoke_scheduler = true; +} + + +void +scheduler_reschedule_ici() +{ + reschedule_needed(); +} + + +static int32 +reschedule_event(timer* /* unused */) +{ + reschedule_needed(); + get_cpu_struct()->preempted = true; + return B_HANDLED_INTERRUPT; +} + + +static inline void +stop_cpu_timers(Thread* fromThread, Thread* toThread) +{ + SpinLocker teamLocker(&fromThread->team->time_lock); + SpinLocker threadLocker(&fromThread->time_lock); + + if (fromThread->HasActiveCPUTimeUserTimers() + || fromThread->team->HasActiveCPUTimeUserTimers()) { + user_timer_stop_cpu_timers(fromThread, toThread); + } +} + + +static inline void +continue_cpu_timers(Thread* thread, cpu_ent* cpu) +{ + SpinLocker teamLocker(&thread->team->time_lock); + SpinLocker threadLocker(&thread->time_lock); + + if (thread->HasActiveCPUTimeUserTimers() + || thread->team->HasActiveCPUTimeUserTimers()) { + user_timer_continue_cpu_timers(thread, cpu->previous_thread); + } +} + + +static void +thread_resumes(Thread* thread) +{ + cpu_ent* cpu = thread->cpu; + + release_spinlock(&cpu->previous_thread->scheduler_lock); + + // continue CPU time based user timers + continue_cpu_timers(thread, cpu); + + // notify the user debugger code + if ((thread->flags & THREAD_FLAGS_DEBUGGER_INSTALLED) != 0) + user_debug_thread_scheduled(thread); +} + + +void +scheduler_new_thread_entry(Thread* thread) +{ + thread_resumes(thread); + + SpinLocker locker(thread->time_lock); + thread->last_time = system_time(); +} + + +/*! Switches the currently running thread. + This is a service function for scheduler implementations. + + \param fromThread The currently running thread. + \param toThread The thread to switch to. Must be different from + \a fromThread. +*/ +static inline void +switch_thread(Thread* fromThread, Thread* toThread) +{ + // notify the user debugger code + if ((fromThread->flags & THREAD_FLAGS_DEBUGGER_INSTALLED) != 0) + user_debug_thread_unscheduled(fromThread); + + // stop CPU time based user timers + stop_cpu_timers(fromThread, toThread); + + // update CPU and Thread structures and perform the context switch + cpu_ent* cpu = fromThread->cpu; + toThread->previous_cpu = toThread->cpu = cpu; + fromThread->cpu = NULL; + cpu->running_thread = toThread; + cpu->previous_thread = fromThread; + + arch_thread_set_current_thread(toThread); + arch_thread_context_switch(fromThread, toThread); + + // The use of fromThread below looks weird, but is correct. fromThread had + // been unscheduled earlier, but is back now. For a thread scheduled the + // first time the same is done in thread.cpp:common_thread_entry(). + thread_resumes(fromThread); +} + + +static inline void +update_thread_times(Thread* oldThread, Thread* nextThread) +{ + SCHEDULER_ENTER_FUNCTION(); + + bigtime_t now = system_time(); + if (oldThread == nextThread) { + SpinLocker _(oldThread->time_lock); + oldThread->kernel_time += now - oldThread->last_time; + oldThread->last_time = now; + } else { + SpinLocker locker(oldThread->time_lock); + oldThread->kernel_time += now - oldThread->last_time; + oldThread->last_time = 0; + locker.Unlock(); + + locker.SetTo(nextThread->time_lock, false); + nextThread->last_time = now; + } + + // If the old thread's team has user time timers, check them now. + Team* team = oldThread->team; + + SpinLocker _(team->time_lock); + if (team->HasActiveUserTimeUserTimers()) + user_timer_check_team_user_timers(team); +} + + +static void +reschedule(int32 nextState) +{ + ASSERT(!are_interrupts_enabled()); + SCHEDULER_ENTER_FUNCTION(); + + SchedulerModeLocker modeLocker; + + Thread* oldThread = thread_get_current_thread(); + + int32 thisCPU = smp_get_current_cpu(); + + CPUEntry* cpu = CPUEntry::GetCPU(thisCPU); + CoreEntry* core = CoreEntry::GetCore(thisCPU); + + TRACE("reschedule(): cpu %ld, current thread = %ld\n", thisCPU, + oldThread->id); + + oldThread->state = nextState; + ThreadData* oldThreadData = oldThread->scheduler_data; + + // return time spent in interrupts + oldThreadData->SetStolenInterruptTime(gCPU[thisCPU].interrupt_time); + + bool enqueueOldThread = false; + bool putOldThreadAtBack = false; + switch (nextState) { + case B_THREAD_RUNNING: + case B_THREAD_READY: + enqueueOldThread = true; + + if (!oldThreadData->IsIdle()) { + oldThreadData->Continues(); + if (oldThreadData->HasQuantumEnded(oldThread->cpu->preempted, + oldThread->has_yielded)) { + TRACE("enqueueing thread %ld into run queue priority =" + " %ld\n", oldThread->id, + oldThreadData->GetEffectivePriority()); + putOldThreadAtBack = true; + } else { + TRACE("putting thread %ld back in run queue priority =" + " %ld\n", oldThread->id, + oldThreadData->GetEffectivePriority()); + putOldThreadAtBack = false; + } + } + + break; + case THREAD_STATE_FREE_ON_RESCHED: + oldThreadData->Dies(); + if (gCPU[thisCPU].disabled) + oldThreadData->UnassignCore(true); + break; + default: + oldThreadData->GoesAway(); + if (gCPU[thisCPU].disabled) + oldThreadData->UnassignCore(true); + + TRACE("not enqueueing thread %ld into run queue next_state = %ld\n", + oldThread->id, nextState); + break; + } + + oldThread->has_yielded = false; + + // select thread with the biggest priority and enqueue back the old thread + ThreadData* nextThreadData; + if (gCPU[thisCPU].disabled) { + if (!oldThreadData->IsIdle()) { + CPURunQueueLocker _(cpu); + + nextThreadData = cpu->PeekIdleThread(); + cpu->Remove(nextThreadData); + + putOldThreadAtBack = oldThread->pinned_to_cpu == 0; + oldThreadData->UnassignCore(true); + } else + nextThreadData = oldThreadData; + } else { + nextThreadData + = cpu->ChooseNextThread(enqueueOldThread ? oldThreadData : NULL, + putOldThreadAtBack); + + // update CPU heap + CoreCPUHeapLocker cpuLocker(core); + cpu->UpdatePriority(nextThreadData->GetEffectivePriority()); + } + + Thread* nextThread = nextThreadData->GetThread(); + ASSERT(!gCPU[thisCPU].disabled || nextThreadData->IsIdle()); + + if (nextThread != oldThread) { + if (enqueueOldThread) { + if (putOldThreadAtBack) + enqueue(oldThread, false); + else + oldThreadData->PutBack(); + } + + acquire_spinlock(&nextThread->scheduler_lock); + } + + TRACE("reschedule(): cpu %ld, next thread = %ld\n", thisCPU, + nextThread->id); + + T(ScheduleThread(nextThread, oldThread)); + + // notify listeners + NotifySchedulerListeners(&SchedulerListener::ThreadScheduled, + oldThread, nextThread); + + ASSERT(nextThreadData->Core() == core); + nextThread->state = B_THREAD_RUNNING; + + // track kernel time (user time is tracked in thread_at_kernel_entry()) + update_thread_times(oldThread, nextThread); + + // track CPU activity + cpu->TrackActivity(oldThreadData, nextThreadData); + + if (nextThread != oldThread || oldThread->cpu->preempted) { + timer* quantumTimer = &oldThread->cpu->quantum_timer; + if (!oldThread->cpu->preempted) + cancel_timer(quantumTimer); + + oldThread->cpu->preempted = false; + if (!nextThreadData->IsIdle()) { + bigtime_t quantum = nextThreadData->GetQuantumLeft(); + add_timer(quantumTimer, &reschedule_event, quantum, + B_ONE_SHOT_RELATIVE_TIMER); + + nextThreadData->Continues(); + } else + gCurrentMode->rebalance_irqs(true); + nextThreadData->StartQuantum(); + + modeLocker.Unlock(); + + SCHEDULER_EXIT_FUNCTION(); + + if (nextThread != oldThread) + switch_thread(oldThread, nextThread); + } +} + + +/*! Runs the scheduler. + Note: expects thread spinlock to be held +*/ +void +scheduler_reschedule(int32 nextState) +{ + ASSERT(!are_interrupts_enabled()); + SCHEDULER_ENTER_FUNCTION(); + + if (!sSchedulerEnabled) { + Thread* thread = thread_get_current_thread(); + if (thread != NULL && nextState != B_THREAD_READY) + panic("scheduler_reschedule_no_op() called in non-ready thread"); + return; + } + + reschedule(nextState); +} + + +status_t +scheduler_on_thread_create(Thread* thread, bool idleThread) +{ + thread->scheduler_data = new(std::nothrow) ThreadData(thread); + if (thread->scheduler_data == NULL) + return B_NO_MEMORY; + return B_OK; +} + + +void +scheduler_on_thread_init(Thread* thread) +{ + ASSERT(thread->scheduler_data != NULL); + + if (thread_is_idle_thread(thread)) { + static int32 sIdleThreadsID; + int32 cpuID = atomic_add(&sIdleThreadsID, 1); + + thread->previous_cpu = &gCPU[cpuID]; + thread->pinned_to_cpu = 1; + + thread->scheduler_data->Init(CoreEntry::GetCore(cpuID)); + } else + thread->scheduler_data->Init(); +} + + +void +scheduler_on_thread_destroy(Thread* thread) +{ + delete thread->scheduler_data; +} + + +/*! This starts the scheduler. Must be run in the context of the initial idle + thread. Interrupts must be disabled and will be disabled when returning. +*/ +void +scheduler_start() +{ + InterruptsSpinLocker _(thread_get_current_thread()->scheduler_lock); + SCHEDULER_ENTER_FUNCTION(); + + reschedule(B_THREAD_READY); +} + + +status_t +scheduler_set_operation_mode(scheduler_mode mode) +{ + if (mode != SCHEDULER_MODE_LOW_LATENCY + && mode != SCHEDULER_MODE_POWER_SAVING) { + return B_BAD_VALUE; + } + + dprintf("scheduler: switching to %s mode\n", sSchedulerModes[mode]->name); + + InterruptsBigSchedulerLocker _; + + gCurrentModeID = mode; + gCurrentMode = sSchedulerModes[mode]; + gCurrentMode->switch_to_mode(); + + ThreadData::ComputeQuantumLengths(); + + return B_OK; +} + + +void +scheduler_set_cpu_enabled(int32 cpuID, bool enabled) +{ +#if KDEBUG + if (are_interrupts_enabled()) + panic("scheduler_set_cpu_enabled: called with interrupts enabled"); +#endif + + dprintf("scheduler: %s CPU %" B_PRId32 "\n", + enabled ? "enabling" : "disabling", cpuID); + + InterruptsBigSchedulerLocker _; + + gCurrentMode->set_cpu_enabled(cpuID, enabled); + + CPUEntry* cpu = &gCPUEntries[cpuID]; + CoreEntry* core = cpu->Core(); + + ASSERT(core->CPUCount() >= 0); + if (enabled) + cpu->Start(); + else { + cpu->UpdatePriority(B_IDLE_PRIORITY); + + ThreadEnqueuer enqueuer; + core->RemoveCPU(cpu, enqueuer); + } + + gCPU[cpuID].disabled = !enabled; + + if (!enabled) { + cpu->Stop(); + + // don't wait until the thread quantum ends + if (smp_get_current_cpu() != cpuID) { + smp_send_ici(cpuID, SMP_MSG_RESCHEDULE, 0, 0, 0, NULL, + SMP_MSG_FLAG_ASYNC); + } + } +} + + +static void +traverse_topology_tree(const cpu_topology_node* node, int packageID, int coreID) +{ + switch (node->level) { + case CPU_TOPOLOGY_SMT: + sCPUToCore[node->id] = coreID; + sCPUToPackage[node->id] = packageID; + return; + + case CPU_TOPOLOGY_CORE: + coreID = node->id; + break; + + case CPU_TOPOLOGY_PACKAGE: + packageID = node->id; + break; + + default: + break; + } + + for (int32 i = 0; i < node->children_count; i++) + traverse_topology_tree(node->children[i], packageID, coreID); +} + + +static status_t +build_topology_mappings(int32& cpuCount, int32& coreCount, int32& packageCount) +{ + cpuCount = smp_get_num_cpus(); + + sCPUToCore = new(std::nothrow) int32[cpuCount]; + if (sCPUToCore == NULL) + return B_NO_MEMORY; + ArrayDeleter cpuToCoreDeleter(sCPUToCore); + + sCPUToPackage = new(std::nothrow) int32[cpuCount]; + if (sCPUToPackage == NULL) + return B_NO_MEMORY; + ArrayDeleter cpuToPackageDeleter(sCPUToPackage); + + coreCount = 0; + for (int32 i = 0; i < cpuCount; i++) { + if (gCPU[i].topology_id[CPU_TOPOLOGY_SMT] == 0) + coreCount++; + } + + packageCount = 0; + for (int32 i = 0; i < cpuCount; i++) { + if (gCPU[i].topology_id[CPU_TOPOLOGY_SMT] == 0 + && gCPU[i].topology_id[CPU_TOPOLOGY_CORE] == 0) { + packageCount++; + } + } + + const cpu_topology_node* root = get_cpu_topology(); + traverse_topology_tree(root, 0, 0); + + cpuToCoreDeleter.Detach(); + cpuToPackageDeleter.Detach(); + return B_OK; +} + + +static status_t +init() +{ + // create logical processor to core and package mappings + int32 cpuCount, coreCount, packageCount; + status_t result = build_topology_mappings(cpuCount, coreCount, + packageCount); + if (result != B_OK) + return result; + + // disable parts of the scheduler logic that are not needed + gSingleCore = coreCount == 1; + gTrackCPULoad = increase_cpu_performance(0) == B_OK; + gTrackCoreLoad = !gSingleCore || gTrackCPULoad; + dprintf("scheduler switches: single core: %s, cpu load tracking: %s," + " core load tracking: %s\n", gSingleCore ? "true" : "false", + gTrackCPULoad ? "true" : "false", + gTrackCoreLoad ? "true" : "false"); + + gCoreCount = coreCount; + gPackageCount = packageCount; + + gCPUEntries = new(std::nothrow) CPUEntry[cpuCount]; + if (gCPUEntries == NULL) + return B_NO_MEMORY; + ArrayDeleter cpuEntriesDeleter(gCPUEntries); + + gCoreEntries = new(std::nothrow) CoreEntry[coreCount]; + if (gCoreEntries == NULL) + return B_NO_MEMORY; + ArrayDeleter coreEntriesDeleter(gCoreEntries); + + gPackageEntries = new(std::nothrow) PackageEntry[packageCount]; + if (gPackageEntries == NULL) + return B_NO_MEMORY; + ArrayDeleter packageEntriesDeleter(gPackageEntries); + + new(&gCoreLoadHeap) CoreLoadHeap(coreCount); + new(&gCoreHighLoadHeap) CoreLoadHeap(coreCount); + + new(&gIdlePackageList) IdlePackageList; + + for (int32 i = 0; i < cpuCount; i++) { + CoreEntry* core = &gCoreEntries[sCPUToCore[i]]; + PackageEntry* package = &gPackageEntries[sCPUToPackage[i]]; + + package->Init(sCPUToPackage[i]); + core->Init(sCPUToCore[i], package); + gCPUEntries[i].Init(i, core); + + core->AddCPU(&gCPUEntries[i]); + } + + packageEntriesDeleter.Detach(); + coreEntriesDeleter.Detach(); + cpuEntriesDeleter.Detach(); + + return B_OK; +} + + +void +scheduler_init() +{ + int32 cpuCount = smp_get_num_cpus(); + dprintf("scheduler_init: found %" B_PRId32 " logical cpu%s and %" B_PRId32 + " cache level%s\n", cpuCount, cpuCount != 1 ? "s" : "", + gCPUCacheLevelCount, gCPUCacheLevelCount != 1 ? "s" : ""); + +#ifdef SCHEDULER_PROFILING + Profiling::Profiler::Initialize(); +#endif + + status_t result = init(); + if (result != B_OK) + panic("scheduler_init: failed to initialize scheduler\n"); + + scheduler_set_operation_mode(SCHEDULER_MODE_LOW_LATENCY); + + init_debug_commands(); + +#if SCHEDULER_TRACING + add_debugger_command_etc("scheduler", &cmd_scheduler, + "Analyze scheduler tracing information", + "\n" + "Analyzes scheduler tracing information for a given thread.\n" + " - ID of the thread.\n", 0); +#endif +} + + +void +scheduler_enable_scheduling() +{ + sSchedulerEnabled = true; } @@ -47,6 +813,7 @@ SchedulerListener::~SchedulerListener() void scheduler_add_listener(struct SchedulerListener* listener) { + InterruptsSpinLocker _(gSchedulerListenersLock); gSchedulerListeners.Add(listener); } @@ -56,52 +823,11 @@ scheduler_add_listener(struct SchedulerListener* listener) void scheduler_remove_listener(struct SchedulerListener* listener) { + InterruptsSpinLocker _(gSchedulerListenersLock); gSchedulerListeners.Remove(listener); } -void -scheduler_init(void) -{ - int32 cpuCount = smp_get_num_cpus(); - dprintf("scheduler_init: found %" B_PRId32 " logical cpu%s\n", cpuCount, - cpuCount != 1 ? "s" : ""); - - if (cpuCount > 1) { -#if 0 - dprintf("scheduler_init: using affine scheduler\n"); - scheduler_affine_init(); -#else - dprintf("scheduler_init: using simple SMP scheduler\n"); - scheduler_simple_smp_init(); -#endif - } else { - dprintf("scheduler_init: using simple scheduler\n"); - scheduler_simple_init(); - } - - // Disable rescheduling until the basic kernel initialization is done and - // CPUs are ready to enable interrupts. - sRescheduleFunction = gScheduler->reschedule; - gScheduler->reschedule = scheduler_reschedule_no_op; - -#if SCHEDULER_TRACING - add_debugger_command_etc("scheduler", &cmd_scheduler, - "Analyze scheduler tracing information", - "\n" - "Analyzes scheduler tracing information for a given thread.\n" - " - ID of the thread.\n", 0); -#endif -} - - -void -scheduler_enable_scheduling(void) -{ - gScheduler->reschedule = sRescheduleFunction; -} - - // #pragma mark - Syscalls @@ -122,7 +848,44 @@ _user_estimate_max_scheduling_latency(thread_id id) } BReference threadReference(thread, true); - // ask the scheduler for the thread's latency - InterruptsSpinLocker locker(gSchedulerLock); - return gScheduler->estimate_max_scheduling_latency(thread); +#ifdef SCHEDULER_PROFILING + InterruptsLocker _; +#endif + + ThreadData* threadData = thread->scheduler_data; + CoreEntry* core = threadData->Core(); + if (core == NULL) + core = &gCoreEntries[get_random() % gCoreCount]; + + int32 threadCount = core->ThreadCount(); + if (core->CPUCount() > 0) + threadCount /= core->CPUCount(); + + if (threadData->GetEffectivePriority() > 0) { + threadCount -= threadCount * THREAD_MAX_SET_PRIORITY + / threadData->GetEffectivePriority(); + } + + return std::min(std::max(threadCount * gCurrentMode->base_quantum, + gCurrentMode->minimal_quantum), + gCurrentMode->maximum_latency); } + + +status_t +_user_set_scheduler_mode(int32 mode) +{ + scheduler_mode schedulerMode = static_cast(mode); + status_t error = scheduler_set_operation_mode(schedulerMode); + if (error == B_OK) + cpu_set_scheduler_mode(schedulerMode); + return error; +} + + +int32 +_user_get_scheduler_mode() +{ + return gCurrentModeID; +} + diff --git a/src/system/kernel/scheduler/scheduler_affine.cpp b/src/system/kernel/scheduler/scheduler_affine.cpp deleted file mode 100644 index c2a5c0c31d..0000000000 --- a/src/system/kernel/scheduler/scheduler_affine.cpp +++ /dev/null @@ -1,567 +0,0 @@ -/* - * Copyright 2009, Rene Gollent, rene@gollent.com. - * Copyright 2008-2011, Ingo Weinhold, ingo_weinhold@gmx.de. - * Copyright 2002-2010, Axel Dörfler, axeld@pinc-software.de. - * Copyright 2002, Angelo Mottola, a.mottola@libero.it. - * Distributed under the terms of the MIT License. - * - * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. - * Distributed under the terms of the NewOS License. - */ - - -/*! The thread scheduler */ - - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "scheduler_common.h" -#include "scheduler_tracing.h" - - -//#define TRACE_SCHEDULER -#ifdef TRACE_SCHEDULER -# define TRACE(x) dprintf_no_syslog x -#else -# define TRACE(x) ; -#endif - -// The run queues. Holds the threads ready to run ordered by priority. -// One queue per schedulable target (CPU, core, etc.). -// TODO: consolidate this such that HT/SMT entities on the same physical core -// share a queue, once we have the necessary API for retrieving the topology -// information -static Thread* sRunQueue[B_MAX_CPU_COUNT]; -static int32 sRunQueueSize[B_MAX_CPU_COUNT]; -static Thread* sIdleThreads; - -const int32 kMaxTrackingQuantums = 5; -const bigtime_t kMinThreadQuantum = 3000; -const bigtime_t kMaxThreadQuantum = 10000; - - -struct scheduler_thread_data { - scheduler_thread_data(void) - { - Init(); - } - - - void Init() - { - fQuantumAverage = 0; - fLastQuantumSlot = 0; - fLastQueue = -1; - memset(fLastThreadQuantums, 0, sizeof(fLastThreadQuantums)); - } - - inline void SetQuantum(int32 quantum) - { - fQuantumAverage -= fLastThreadQuantums[fLastQuantumSlot]; - fLastThreadQuantums[fLastQuantumSlot] = quantum; - fQuantumAverage += quantum; - if (fLastQuantumSlot < kMaxTrackingQuantums - 1) - ++fLastQuantumSlot; - else - fLastQuantumSlot = 0; - } - - inline int32 GetAverageQuantumUsage() const - { - return fQuantumAverage / kMaxTrackingQuantums; - } - - int32 fQuantumAverage; - int32 fLastThreadQuantums[kMaxTrackingQuantums]; - int16 fLastQuantumSlot; - int32 fLastQueue; -}; - - -static int -dump_run_queue(int argc, char **argv) -{ - Thread *thread = NULL; - - for (int32 i = 0; i < smp_get_num_cpus(); i++) { - thread = sRunQueue[i]; - kprintf("Run queue for cpu %" B_PRId32 " (%" B_PRId32 " threads)\n", i, - sRunQueueSize[i]); - if (sRunQueueSize[i] > 0) { - kprintf("thread id priority avg. quantum name\n"); - while (thread) { - kprintf("%p %-7" B_PRId32 " %-8" B_PRId32 " %-12" B_PRId32 - " %s\n", thread, thread->id, thread->priority, - thread->scheduler_data->GetAverageQuantumUsage(), - thread->name); - thread = thread->queue_next; - } - } - } - return 0; -} - - -/*! Returns the most idle CPU based on the active time counters. - Note: thread lock must be held when entering this function -*/ -static int32 -affine_get_most_idle_cpu() -{ - int32 targetCPU = -1; - for (int32 i = 0; i < smp_get_num_cpus(); i++) { - if (gCPU[i].disabled) - continue; - if (targetCPU < 0 || sRunQueueSize[i] < sRunQueueSize[targetCPU]) - targetCPU = i; - } - - return targetCPU; -} - - -/*! Enqueues the thread into the run queue. - Note: thread lock must be held when entering this function -*/ -static void -affine_enqueue_in_run_queue(Thread *thread) -{ - int32 targetCPU = -1; - if (thread->pinned_to_cpu > 0) - targetCPU = thread->previous_cpu->cpu_num; - else if (thread->previous_cpu == NULL || thread->previous_cpu->disabled) - targetCPU = affine_get_most_idle_cpu(); - else - targetCPU = thread->previous_cpu->cpu_num; - - thread->state = thread->next_state = B_THREAD_READY; - - if (thread->priority == B_IDLE_PRIORITY) { - thread->queue_next = sIdleThreads; - sIdleThreads = thread; - } else { - Thread *curr, *prev; - for (curr = sRunQueue[targetCPU], prev = NULL; curr - && curr->priority >= thread->next_priority; - curr = curr->queue_next) { - if (prev) - prev = prev->queue_next; - else - prev = sRunQueue[targetCPU]; - } - - T(EnqueueThread(thread, prev, curr)); - sRunQueueSize[targetCPU]++; - thread->queue_next = curr; - if (prev) - prev->queue_next = thread; - else - sRunQueue[targetCPU] = thread; - - thread->scheduler_data->fLastQueue = targetCPU; - } - - thread->next_priority = thread->priority; - - // notify listeners - NotifySchedulerListeners(&SchedulerListener::ThreadEnqueuedInRunQueue, - thread); - - if (thread->priority > gCPU[targetCPU].running_thread->priority) { - if (targetCPU == smp_get_current_cpu()) { - gCPU[targetCPU].invoke_scheduler = true; - gCPU[targetCPU].invoke_scheduler_if_idle = false; - } else { - smp_send_ici(targetCPU, SMP_MSG_RESCHEDULE, 0, 0, 0, NULL, - SMP_MSG_FLAG_ASYNC); - } - } -} - - -/*! Dequeues the thread after the given \a prevThread from the run queue. -*/ -static inline Thread * -dequeue_from_run_queue(Thread *prevThread, int32 currentCPU) -{ - Thread *resultThread = NULL; - if (prevThread != NULL) { - resultThread = prevThread->queue_next; - prevThread->queue_next = resultThread->queue_next; - } else { - resultThread = sRunQueue[currentCPU]; - sRunQueue[currentCPU] = resultThread->queue_next; - } - sRunQueueSize[currentCPU]--; - resultThread->scheduler_data->fLastQueue = -1; - - return resultThread; -} - - -/*! Looks for a possible thread to grab/run from another CPU. - Note: thread lock must be held when entering this function -*/ -static Thread * -steal_thread_from_other_cpus(int32 currentCPU) -{ - // look through the active CPUs - find the one - // that has a) threads available to steal, and - // b) out of those, the one that's the most CPU-bound - // TODO: make this more intelligent along with enqueue - // - we need to try and maintain a reasonable balance - // in run queue sizes across CPUs, and also try to maintain - // an even distribution of cpu bound / interactive threads - int32 targetCPU = -1; - for (int32 i = 0; i < smp_get_num_cpus(); i++) { - // skip CPUs that have either no or only one thread - if (i == currentCPU || sRunQueueSize[i] < 2) - continue; - - // out of the CPUs with threads available to steal, - // pick whichever one is generally the most CPU bound. - if (targetCPU < 0 - || sRunQueue[i]->priority > sRunQueue[targetCPU]->priority - || (sRunQueue[i]->priority == sRunQueue[targetCPU]->priority - && sRunQueueSize[i] > sRunQueueSize[targetCPU])) - targetCPU = i; - } - - if (targetCPU < 0) - return NULL; - - Thread* nextThread = sRunQueue[targetCPU]; - Thread* prevThread = NULL; - - while (nextThread != NULL) { - // grab the highest priority non-pinned thread - // out of this CPU's queue, dequeue and return it - if (nextThread->pinned_to_cpu <= 0) { - dequeue_from_run_queue(prevThread, targetCPU); - return nextThread; - } - - prevThread = nextThread; - nextThread = nextThread->queue_next; - } - - return NULL; -} - - -/*! Sets the priority of a thread. - Note: thread lock must be held when entering this function -*/ -static void -affine_set_thread_priority(Thread *thread, int32 priority) -{ - int32 targetCPU = -1; - - if (priority == thread->priority) - return; - - if (thread->state != B_THREAD_READY) { - thread->priority = priority; - return; - } - - // The thread is in the run queue. We need to remove it and re-insert it at - // a new position. - - T(RemoveThread(thread)); - - // notify listeners - NotifySchedulerListeners(&SchedulerListener::ThreadRemovedFromRunQueue, - thread); - - // search run queues for the thread - Thread *item = NULL, *prev = NULL; - targetCPU = thread->scheduler_data->fLastQueue; - - for (item = sRunQueue[targetCPU], prev = NULL; item && item != thread; - item = item->queue_next) { - if (prev) - prev = prev->queue_next; - else - prev = item; - } - - ASSERT(item == thread); - - // remove the thread - thread = dequeue_from_run_queue(prev, targetCPU); - - // set priority and re-insert - thread->priority = thread->next_priority = priority; - affine_enqueue_in_run_queue(thread); -} - - -static bigtime_t -affine_estimate_max_scheduling_latency(Thread* thread) -{ - // TODO: This is probably meant to be called periodically to return the - // current estimate depending on the system usage; we return fixed estimates - // per thread priority, though. - - if (thread->priority >= B_REAL_TIME_DISPLAY_PRIORITY) - return kMinThreadQuantum / 4; - if (thread->priority >= B_DISPLAY_PRIORITY) - return kMinThreadQuantum; - if (thread->priority < B_NORMAL_PRIORITY) - return 2 * kMaxThreadQuantum; - - return 2 * kMinThreadQuantum; -} - - -static int32 -reschedule_event(timer *unused) -{ - // This function is called as a result of the timer event set by the - // scheduler. Make sure the reschedule() is invoked. - thread_get_current_thread()->cpu->invoke_scheduler = true; - thread_get_current_thread()->cpu->invoke_scheduler_if_idle = false; - thread_get_current_thread()->cpu->preempted = 1; - return B_HANDLED_INTERRUPT; -} - - -/*! Runs the scheduler. - Note: expects thread spinlock to be held -*/ -static void -affine_reschedule(void) -{ - int32 currentCPU = smp_get_current_cpu(); - Thread *oldThread = thread_get_current_thread(); - - // check whether we're only supposed to reschedule, if the current thread - // is idle - if (oldThread->cpu->invoke_scheduler) { - oldThread->cpu->invoke_scheduler = false; - if (oldThread->cpu->invoke_scheduler_if_idle - && oldThread->priority != B_IDLE_PRIORITY) { - oldThread->cpu->invoke_scheduler_if_idle = false; - return; - } - } - - Thread *nextThread, *prevThread; - - TRACE(("reschedule(): cpu %ld, cur_thread = %ld\n", currentCPU, oldThread->id)); - - oldThread->state = oldThread->next_state; - switch (oldThread->next_state) { - case B_THREAD_RUNNING: - case B_THREAD_READY: - TRACE(("enqueueing thread %ld into run q. pri = %ld\n", oldThread->id, oldThread->priority)); - affine_enqueue_in_run_queue(oldThread); - break; - case B_THREAD_SUSPENDED: - TRACE(("reschedule(): suspending thread %ld\n", oldThread->id)); - break; - case THREAD_STATE_FREE_ON_RESCHED: - break; - default: - TRACE(("not enqueueing thread %ld into run q. next_state = %ld\n", oldThread->id, oldThread->next_state)); - break; - } - - nextThread = sRunQueue[currentCPU]; - prevThread = NULL; - - if (sRunQueue[currentCPU] != NULL) { - TRACE(("dequeueing next thread from cpu %ld\n", currentCPU)); - // select next thread from the run queue - while (nextThread->queue_next) { - // always extract real time threads - if (nextThread->priority >= B_FIRST_REAL_TIME_PRIORITY) - break; - - // find next thread with lower priority - Thread *lowerNextThread = nextThread->queue_next; - Thread *lowerPrevThread = nextThread; - int32 priority = nextThread->priority; - - while (lowerNextThread != NULL - && priority == lowerNextThread->priority) { - lowerPrevThread = lowerNextThread; - lowerNextThread = lowerNextThread->queue_next; - } - if (lowerNextThread == NULL) - break; - - int32 priorityDiff = priority - lowerNextThread->priority; - if (priorityDiff > 15) - break; - - // skip normal threads sometimes - // (twice as probable per priority level) - if ((fast_random_value() >> (15 - priorityDiff)) != 0) - break; - - nextThread = lowerNextThread; - prevThread = lowerPrevThread; - } - - TRACE(("dequeuing thread %ld from cpu %ld\n", nextThread->id, - currentCPU)); - // extract selected thread from the run queue - dequeue_from_run_queue(prevThread, currentCPU); - } else { - if (!gCPU[currentCPU].disabled) { - TRACE(("CPU %ld stealing thread from other CPUs\n", currentCPU)); - nextThread = steal_thread_from_other_cpus(currentCPU); - } else - nextThread = NULL; - - if (nextThread == NULL) { - TRACE(("No threads to steal, grabbing from idle pool\n")); - // no other CPU had anything for us to take, - // grab one from the kernel's idle pool - nextThread = sIdleThreads; - if (nextThread) - sIdleThreads = nextThread->queue_next; - } - } - - if (!nextThread) - panic("reschedule(): run queue is empty!\n"); - - T(ScheduleThread(nextThread, oldThread)); - - // notify listeners - NotifySchedulerListeners(&SchedulerListener::ThreadScheduled, - oldThread, nextThread); - - nextThread->state = B_THREAD_RUNNING; - nextThread->next_state = B_THREAD_READY; - oldThread->was_yielded = false; - - // track kernel time (user time is tracked in thread_at_kernel_entry()) - scheduler_update_thread_times(oldThread, nextThread); - - // track CPU activity - if (!thread_is_idle_thread(oldThread)) { - bigtime_t activeTime = - (oldThread->kernel_time - oldThread->cpu->last_kernel_time) - + (oldThread->user_time - oldThread->cpu->last_user_time); - oldThread->cpu->active_time += activeTime; - scheduler_thread_data *data = oldThread->scheduler_data; - data->SetQuantum(activeTime); - } - - if (!thread_is_idle_thread(nextThread)) { - oldThread->cpu->last_kernel_time = nextThread->kernel_time; - oldThread->cpu->last_user_time = nextThread->user_time; - } - - if (nextThread != oldThread || oldThread->cpu->preempted) { - timer *quantumTimer = &oldThread->cpu->quantum_timer; - if (!oldThread->cpu->preempted) - cancel_timer(quantumTimer); - oldThread->cpu->preempted = 0; - - // we do not adjust the quantum for the idle thread as it is going to be - // preempted most of the time and would likely get the longer quantum - // over time, indeed we use a smaller quantum to avoid running idle too - // long - bigtime_t quantum = kMinThreadQuantum; - // give CPU-bound background threads a larger quantum size - // to minimize unnecessary context switches if the system is idle - if (nextThread->priority != B_IDLE_PRIORITY - && nextThread->scheduler_data->GetAverageQuantumUsage() - > (kMinThreadQuantum >> 1) - && nextThread->priority < B_NORMAL_PRIORITY) - quantum = kMaxThreadQuantum; - - if (!thread_is_idle_thread(nextThread)) { - add_timer(quantumTimer, &reschedule_event, quantum, - B_ONE_SHOT_RELATIVE_TIMER | B_TIMER_ACQUIRE_SCHEDULER_LOCK); - } - - if (nextThread != oldThread) - scheduler_switch_thread(oldThread, nextThread); - } -} - - -static status_t -affine_on_thread_create(Thread* thread, bool idleThread) -{ - // we don't need a data structure for the idle threads - if (idleThread) { - thread->scheduler_data = NULL; - return B_OK; - } - - thread->scheduler_data = new(std::nothrow) scheduler_thread_data(); - if (thread->scheduler_data == NULL) - return B_NO_MEMORY; - return B_OK; -} - - -static void -affine_on_thread_init(Thread* thread) -{ - ((scheduler_thread_data *)(thread->scheduler_data))->Init(); -} - - -static void -affine_on_thread_destroy(Thread* thread) -{ - delete thread->scheduler_data; -} - - -/*! This starts the scheduler. Must be run in the context of the initial idle - thread. Interrupts must be disabled and will be disabled when returning. -*/ -static void -affine_start(void) -{ - SpinLocker schedulerLocker(gSchedulerLock); - - affine_reschedule(); -} - - -static scheduler_ops kAffineOps = { - affine_enqueue_in_run_queue, - affine_reschedule, - affine_set_thread_priority, - affine_estimate_max_scheduling_latency, - affine_on_thread_create, - affine_on_thread_init, - affine_on_thread_destroy, - affine_start -}; - - -// #pragma mark - - - -void -scheduler_affine_init() -{ - gScheduler = &kAffineOps; - memset(sRunQueue, 0, sizeof(sRunQueue)); - memset(sRunQueueSize, 0, sizeof(sRunQueueSize)); - add_debugger_command_etc("run_queue", &dump_run_queue, - "List threads in run queue", "\nLists threads in run queue", 0); -} diff --git a/src/system/kernel/scheduler/scheduler_affine.h b/src/system/kernel/scheduler/scheduler_affine.h deleted file mode 100644 index 1762fe37a7..0000000000 --- a/src/system/kernel/scheduler/scheduler_affine.h +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Copyright 2009, Rene Gollent, rene@gollent.com. - * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de. - * Distributed under the terms of the MIT License. - */ -#ifndef KERNEL_SCHEDULER_AFFINE_H -#define KERNEL_SCHEDULER_AFFINE_H - - -void scheduler_affine_init(); - - -#endif // KERNEL_SCHEDULER_AFFINE_H diff --git a/src/system/kernel/scheduler/scheduler_common.h b/src/system/kernel/scheduler/scheduler_common.h index 0de57db2b6..96e7d867ce 100644 --- a/src/system/kernel/scheduler/scheduler_common.h +++ b/src/system/kernel/scheduler/scheduler_common.h @@ -1,4 +1,5 @@ /* + * Copyright 2013, Paweł Dziepak, pdziepak@quarnos.org. * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de. * Distributed under the terms of the MIT License. */ @@ -6,81 +7,51 @@ #define KERNEL_SCHEDULER_COMMON_H +#include + +#include #include +#include #include +#include #include +#include + +#include "RunQueue.h" -/*! Switches the currently running thread. - This is a service function for scheduler implementations. - - \param fromThread The currently running thread. - \param toThread The thread to switch to. Must be different from - \a fromThread. -*/ -static inline void -scheduler_switch_thread(Thread* fromThread, Thread* toThread) -{ - // notify the user debugger code - if ((fromThread->flags & THREAD_FLAGS_DEBUGGER_INSTALLED) != 0) - user_debug_thread_unscheduled(fromThread); - - // stop CPU time based user timers - if (fromThread->HasActiveCPUTimeUserTimers() - || fromThread->team->HasActiveCPUTimeUserTimers()) { - user_timer_stop_cpu_timers(fromThread, toThread); - } - - // update CPU and Thread structures and perform the context switch - cpu_ent* cpu = fromThread->cpu; - toThread->previous_cpu = toThread->cpu = cpu; - fromThread->cpu = NULL; - cpu->running_thread = toThread; - cpu->previous_thread = fromThread; - - arch_thread_set_current_thread(toThread); - arch_thread_context_switch(fromThread, toThread); - - // The use of fromThread below looks weird, but is correct. fromThread had - // been unscheduled earlier, but is back now. For a thread scheduled the - // first time the same is done in thread.cpp:common_thread_entry(). - - // continue CPU time based user timers - if (fromThread->HasActiveCPUTimeUserTimers() - || fromThread->team->HasActiveCPUTimeUserTimers()) { - user_timer_continue_cpu_timers(fromThread, cpu->previous_thread); - } - - // notify the user debugger code - if ((fromThread->flags & THREAD_FLAGS_DEBUGGER_INSTALLED) != 0) - user_debug_thread_scheduled(fromThread); -} +//#define TRACE_SCHEDULER +#ifdef TRACE_SCHEDULER +# define TRACE(...) dprintf_no_syslog(__VA_ARGS__) +#else +# define TRACE(...) do { } while (false) +#endif -static inline void -scheduler_update_thread_times(Thread* oldThread, Thread* nextThread) -{ - bigtime_t now = system_time(); - if (oldThread == nextThread) { - acquire_spinlock(&oldThread->time_lock); - oldThread->kernel_time += now - oldThread->last_time; - oldThread->last_time = now; - release_spinlock(&oldThread->time_lock); - } else { - acquire_spinlock(&oldThread->time_lock); - oldThread->kernel_time += now - oldThread->last_time; - release_spinlock(&oldThread->time_lock); +namespace Scheduler { - acquire_spinlock(&nextThread->time_lock); - nextThread->last_time = now; - release_spinlock(&nextThread->time_lock); - } - // If the old thread's team has user time timers, check them now. - Team* team = oldThread->team; - if (team->HasActiveUserTimeUserTimers()) - user_timer_check_team_user_timers(team); -} +struct CPUEntry; +struct CoreEntry; + +const int kLowLoad = kMaxLoad * 20 / 100; +const int kTargetLoad = kMaxLoad * 55 / 100; +const int kHighLoad = kMaxLoad * 70 / 100; +const int kMediumLoad = (kHighLoad + kTargetLoad) / 2; +const int kVeryHighLoad = (kMaxLoad + kHighLoad) / 2; + +const int kLoadDifference = kMaxLoad * 20 / 100; + +extern bool gSingleCore; +extern bool gTrackCoreLoad; +extern bool gTrackCPULoad; + + +void init_debug_commands(); + + +} // namespace Scheduler #endif // KERNEL_SCHEDULER_COMMON_H + diff --git a/src/system/kernel/scheduler/scheduler_cpu.cpp b/src/system/kernel/scheduler/scheduler_cpu.cpp new file mode 100644 index 0000000000..9cbee92710 --- /dev/null +++ b/src/system/kernel/scheduler/scheduler_cpu.cpp @@ -0,0 +1,735 @@ +/* + * Copyright 2013, Paweł Dziepak, pdziepak@quarnos.org. + * Distributed under the terms of the MIT License. + */ + + +#include "scheduler_cpu.h" + +#include + +#include + +#include "scheduler_thread.h" + + +namespace Scheduler { + + +CPUEntry* gCPUEntries; + +CoreEntry* gCoreEntries; +CoreLoadHeap gCoreLoadHeap; +CoreLoadHeap gCoreHighLoadHeap; +rw_spinlock gCoreHeapsLock = B_RW_SPINLOCK_INITIALIZER; +int32 gCoreCount; + +PackageEntry* gPackageEntries; +IdlePackageList gIdlePackageList; +rw_spinlock gIdlePackageLock = B_RW_SPINLOCK_INITIALIZER; +int32 gPackageCount; + + +} // namespace Scheduler + +using namespace Scheduler; + + +class Scheduler::DebugDumper { +public: + static void DumpCPURunQueue(CPUEntry* cpu); + static void DumpCoreRunQueue(CoreEntry* core); + static void DumpIdleCoresInPackage(PackageEntry* package); +}; + + +static CPUPriorityHeap sDebugCPUHeap; +static CoreLoadHeap sDebugCoreHeap; + + +void +ThreadRunQueue::Dump() const +{ + ThreadRunQueue::ConstIterator iterator = GetConstIterator(); + if (!iterator.HasNext()) + kprintf("Run queue is empty.\n"); + else { + kprintf("thread id priority penalty name\n"); + while (iterator.HasNext()) { + ThreadData* threadData = iterator.Next(); + Thread* thread = threadData->GetThread(); + + kprintf("%p %-7" B_PRId32 " %-8" B_PRId32 " %-8" B_PRId32 " %s\n", + thread, thread->id, thread->priority, + thread->priority - threadData->GetEffectivePriority(), + thread->name); + } + } +} + + +CPUEntry::CPUEntry() + : + fLoad(0), + fMeasureActiveTime(0), + fMeasureTime(0) +{ + B_INITIALIZE_RW_SPINLOCK(&fSchedulerModeLock); + B_INITIALIZE_SPINLOCK(&fQueueLock); +} + + +void +CPUEntry::Init(int32 id, CoreEntry* core) +{ + fCPUNumber = id; + fCore = core; +} + + +void +CPUEntry::Start() +{ + fLoad = 0; + fCore->AddCPU(this); +} + + +void +CPUEntry::Stop() +{ + cpu_ent* entry = &gCPU[fCPUNumber]; + + // get rid of irqs + SpinLocker locker(entry->irqs_lock); + irq_assignment* irq + = (irq_assignment*)list_get_first_item(&entry->irqs); + while (irq != NULL) { + locker.Unlock(); + + assign_io_interrupt_to_cpu(irq->irq, -1); + + locker.Lock(); + irq = (irq_assignment*)list_get_first_item(&entry->irqs); + } + locker.Unlock(); +} + + +void +CPUEntry::PushFront(ThreadData* thread, int32 priority) +{ + SCHEDULER_ENTER_FUNCTION(); + fRunQueue.PushFront(thread, priority); +} + + +void +CPUEntry::PushBack(ThreadData* thread, int32 priority) +{ + SCHEDULER_ENTER_FUNCTION(); + fRunQueue.PushBack(thread, priority); +} + + +void +CPUEntry::Remove(ThreadData* thread) +{ + SCHEDULER_ENTER_FUNCTION(); + ASSERT(thread->IsEnqueued()); + thread->SetDequeued(); + fRunQueue.Remove(thread); +} + + +inline ThreadData* +CoreEntry::PeekThread() const +{ + SCHEDULER_ENTER_FUNCTION(); + return fRunQueue.PeekMaximum(); +} + + +inline ThreadData* +CPUEntry::PeekThread() const +{ + SCHEDULER_ENTER_FUNCTION(); + return fRunQueue.PeekMaximum(); +} + + +ThreadData* +CPUEntry::PeekIdleThread() const +{ + SCHEDULER_ENTER_FUNCTION(); + return fRunQueue.GetHead(B_IDLE_PRIORITY); +} + + +void +CPUEntry::UpdatePriority(int32 priority) +{ + SCHEDULER_ENTER_FUNCTION(); + + ASSERT(!gCPU[fCPUNumber].disabled); + + int32 oldPriority = CPUPriorityHeap::GetKey(this); + if (oldPriority == priority) + return; + fCore->CPUHeap()->ModifyKey(this, priority); + + if (oldPriority == B_IDLE_PRIORITY) + fCore->CPUWakesUp(this); + else if (priority == B_IDLE_PRIORITY) + fCore->CPUGoesIdle(this); +} + + +void +CPUEntry::ComputeLoad() +{ + SCHEDULER_ENTER_FUNCTION(); + + ASSERT(gTrackCPULoad); + ASSERT(!gCPU[fCPUNumber].disabled); + ASSERT(fCPUNumber == smp_get_current_cpu()); + + int oldLoad = compute_load(fMeasureTime, fMeasureActiveTime, fLoad, + system_time()); + if (oldLoad < 0) + return; + + if (fLoad > kVeryHighLoad) + gCurrentMode->rebalance_irqs(false); +} + + +ThreadData* +CPUEntry::ChooseNextThread(ThreadData* oldThread, bool putAtBack) +{ + SCHEDULER_ENTER_FUNCTION(); + + int32 oldPriority = -1; + if (oldThread != NULL) + oldPriority = oldThread->GetEffectivePriority(); + + CPURunQueueLocker cpuLocker(this); + + ThreadData* pinnedThread = fRunQueue.PeekMaximum(); + int32 pinnedPriority = -1; + if (pinnedThread != NULL) + pinnedPriority = pinnedThread->GetEffectivePriority(); + + CoreRunQueueLocker coreLocker(fCore); + + ThreadData* sharedThread = fCore->PeekThread(); + ASSERT(sharedThread != NULL || pinnedThread != NULL || oldThread != NULL); + + int32 sharedPriority = -1; + if (sharedThread != NULL) + sharedPriority = sharedThread->GetEffectivePriority(); + + int32 rest = std::max(pinnedPriority, sharedPriority); + if (oldPriority > rest || (!putAtBack && oldPriority == rest)) + return oldThread; + + if (sharedPriority > pinnedPriority) { + fCore->Remove(sharedThread); + return sharedThread; + } + + coreLocker.Unlock(); + + Remove(pinnedThread); + return pinnedThread; +} + + +void +CPUEntry::TrackActivity(ThreadData* oldThreadData, ThreadData* nextThreadData) +{ + SCHEDULER_ENTER_FUNCTION(); + + cpu_ent* cpuEntry = &gCPU[fCPUNumber]; + + Thread* oldThread = oldThreadData->GetThread(); + if (!thread_is_idle_thread(oldThread)) { + bigtime_t active + = (oldThread->kernel_time - cpuEntry->last_kernel_time) + + (oldThread->user_time - cpuEntry->last_user_time); + + WriteSequentialLocker locker(cpuEntry->active_time_lock); + cpuEntry->active_time += active; + locker.Unlock(); + + fMeasureActiveTime += active; + fCore->IncreaseActiveTime(active); + + oldThreadData->UpdateActivity(active); + } + + if (gTrackCPULoad) { + if (!cpuEntry->disabled) + ComputeLoad(); + _RequestPerformanceLevel(nextThreadData); + } + + Thread* nextThread = nextThreadData->GetThread(); + if (!thread_is_idle_thread(nextThread)) { + cpuEntry->last_kernel_time = nextThread->kernel_time; + cpuEntry->last_user_time = nextThread->user_time; + + nextThreadData->SetLastInterruptTime(cpuEntry->interrupt_time); + } +} + + +void +CPUEntry::_RequestPerformanceLevel(ThreadData* threadData) +{ + SCHEDULER_ENTER_FUNCTION(); + + if (gCPU[fCPUNumber].disabled) { + decrease_cpu_performance(kCPUPerformanceScaleMax); + return; + } + + int32 load = std::max(threadData->GetLoad(), fCore->GetLoad()); + ASSERT(load >= 0 && load <= kMaxLoad); + + if (load < kTargetLoad) { + int32 delta = kTargetLoad - load; + + delta *= kTargetLoad; + delta /= kCPUPerformanceScaleMax; + + decrease_cpu_performance(delta); + } else { + int32 delta = load - kTargetLoad; + delta *= kMaxLoad - kTargetLoad; + delta /= kCPUPerformanceScaleMax; + + increase_cpu_performance(delta); + } +} + + +CPUPriorityHeap::CPUPriorityHeap(int32 cpuCount) + : + Heap(cpuCount) +{ +} + + +void +CPUPriorityHeap::Dump() +{ + kprintf("cpu priority load\n"); + CPUEntry* entry = PeekRoot(); + while (entry) { + int32 cpu = entry->ID(); + int32 key = GetKey(entry); + kprintf("%3" B_PRId32 " %8" B_PRId32 " %3" B_PRId32 "%%\n", cpu, key, + entry->GetLoad() / 10); + + RemoveRoot(); + sDebugCPUHeap.Insert(entry, key); + + entry = PeekRoot(); + } + + entry = sDebugCPUHeap.PeekRoot(); + while (entry) { + int32 key = GetKey(entry); + sDebugCPUHeap.RemoveRoot(); + Insert(entry, key); + entry = sDebugCPUHeap.PeekRoot(); + } +} + + +CoreEntry::CoreEntry() + : + fCPUCount(0), + fIdleCPUCount(0), + fStarvationCounter(0), + fStarvationCounterIdle(0), + fThreadCount(0), + fActiveTime(0), + fLoad(0), + fHighLoad(false), + fLastLoadUpdate(0) +{ + B_INITIALIZE_SPINLOCK(&fCPULock); + B_INITIALIZE_SPINLOCK(&fQueueLock); + B_INITIALIZE_SEQLOCK(&fActiveTimeLock); +} + + +void +CoreEntry::Init(int32 id, PackageEntry* package) +{ + fCoreID = id; + fPackage = package; +} + + +void +CoreEntry::PushFront(ThreadData* thread, int32 priority) +{ + SCHEDULER_ENTER_FUNCTION(); + + fRunQueue.PushFront(thread, priority); + atomic_add(&fThreadCount, 1); +} + + +void +CoreEntry::PushBack(ThreadData* thread, int32 priority) +{ + SCHEDULER_ENTER_FUNCTION(); + + fRunQueue.PushBack(thread, priority); + atomic_add(&fThreadCount, 1); +} + + +void +CoreEntry::Remove(ThreadData* thread) +{ + SCHEDULER_ENTER_FUNCTION(); + + ASSERT(thread->IsEnqueued()); + thread->SetDequeued(); + + ASSERT(!thread_is_idle_thread(thread->GetThread())); + if (thread->GetEffectivePriority() == B_LOWEST_ACTIVE_PRIORITY + || thread->IsCPUBound()) { + atomic_add(&fStarvationCounter, 1); + } + + fRunQueue.Remove(thread); + atomic_add(&fThreadCount, -1); +} + + +void +CoreEntry::UpdateLoad(int32 delta) +{ + SCHEDULER_ENTER_FUNCTION(); + + ASSERT(gTrackCoreLoad); + + atomic_add(&fLoad, delta); + + bigtime_t now = system_time(); + if (now < kLoadMeasureInterval + fLastLoadUpdate) + return; + if (!try_acquire_write_spinlock(&gCoreHeapsLock)) + return; + WriteSpinLocker coreLocker(gCoreHeapsLock, true); + + fLastLoadUpdate = now; + + int32 newKey = GetLoad(); + int32 oldKey = CoreLoadHeap::GetKey(this); + + ASSERT(oldKey >= 0); + ASSERT(newKey >= 0); + + if (oldKey == newKey) + return; + + if (newKey > kHighLoad) { + if (!fHighLoad) { + gCoreLoadHeap.ModifyKey(this, -1); + ASSERT(gCoreLoadHeap.PeekMinimum() == this); + gCoreLoadHeap.RemoveMinimum(); + + gCoreHighLoadHeap.Insert(this, newKey); + + fHighLoad = true; + } else + gCoreHighLoadHeap.ModifyKey(this, newKey); + } else if (newKey < kMediumLoad) { + if (fHighLoad) { + gCoreHighLoadHeap.ModifyKey(this, -1); + ASSERT(gCoreHighLoadHeap.PeekMinimum() == this); + gCoreHighLoadHeap.RemoveMinimum(); + + gCoreLoadHeap.Insert(this, newKey); + + fHighLoad = false; + } else + gCoreLoadHeap.ModifyKey(this, newKey); + } else { + if (fHighLoad) + gCoreHighLoadHeap.ModifyKey(this, newKey); + else + gCoreLoadHeap.ModifyKey(this, newKey); + } +} + + +void +CoreEntry::AddCPU(CPUEntry* cpu) +{ + ASSERT(fCPUCount >= 0); + ASSERT(fIdleCPUCount >= 0); + + fIdleCPUCount++; + if (fCPUCount++ == 0) { + // core has been reenabled + fLoad = 0; + fHighLoad = false; + gCoreLoadHeap.Insert(this, 0); + + fPackage->AddIdleCore(this); + } + + fCPUHeap.Insert(cpu, B_IDLE_PRIORITY); +} + + +void +CoreEntry::RemoveCPU(CPUEntry* cpu, ThreadProcessing& threadPostProcessing) +{ + ASSERT(fCPUCount > 0); + ASSERT(fIdleCPUCount > 0); + + fIdleCPUCount--; + if (--fCPUCount == 0) { + // unassign threads + thread_map(CoreEntry::_UnassignThread, this); + + // core has been disabled + if (fHighLoad) { + gCoreHighLoadHeap.ModifyKey(this, -1); + ASSERT(gCoreHighLoadHeap.PeekMinimum() == this); + gCoreHighLoadHeap.RemoveMinimum(); + } else { + gCoreLoadHeap.ModifyKey(this, -1); + ASSERT(gCoreLoadHeap.PeekMinimum() == this); + gCoreLoadHeap.RemoveMinimum(); + } + + fPackage->RemoveIdleCore(this); + + // get rid of threads + while (fRunQueue.PeekMaximum() != NULL) { + ThreadData* threadData = fRunQueue.PeekMaximum(); + + Remove(threadData); + + ASSERT(threadData->Core() == NULL); + threadPostProcessing(threadData); + } + + fThreadCount = 0; + } + + fCPUHeap.ModifyKey(cpu, -1); + ASSERT(fCPUHeap.PeekRoot() == cpu); + fCPUHeap.RemoveRoot(); + + ASSERT(cpu->GetLoad() >= 0 && cpu->GetLoad() <= kMaxLoad); + ASSERT(fLoad >= 0); +} + + +/* static */ void +CoreEntry::_UnassignThread(Thread* thread, void* data) +{ + CoreEntry* core = static_cast(data); + ThreadData* threadData = thread->scheduler_data; + + if (threadData->Core() == core && thread->pinned_to_cpu == 0) + threadData->UnassignCore(); +} + + +CoreLoadHeap::CoreLoadHeap(int32 coreCount) + : + MinMaxHeap(coreCount) +{ +} + + +void +CoreLoadHeap::Dump() +{ + CoreEntry* entry = PeekMinimum(); + while (entry) { + int32 key = GetKey(entry); + + kprintf("%4" B_PRId32 " %3" B_PRId32 "%% %7" B_PRId32 "\n", entry->ID(), + entry->GetLoad() / 10, entry->ThreadCount()); + + RemoveMinimum(); + sDebugCoreHeap.Insert(entry, key); + + entry = PeekMinimum(); + } + + entry = sDebugCoreHeap.PeekMinimum(); + while (entry) { + int32 key = GetKey(entry); + sDebugCoreHeap.RemoveMinimum(); + Insert(entry, key); + entry = sDebugCoreHeap.PeekMinimum(); + } +} + + +PackageEntry::PackageEntry() + : + fIdleCoreCount(0), + fCoreCount(0) +{ + B_INITIALIZE_RW_SPINLOCK(&fCoreLock); +} + + +void +PackageEntry::Init(int32 id) +{ + fPackageID = id; +} + + +void +PackageEntry::AddIdleCore(CoreEntry* core) +{ + fCoreCount++; + fIdleCoreCount++; + fIdleCores.Add(core); + + if (fCoreCount == 1) + gIdlePackageList.Add(this); +} + + +void +PackageEntry::RemoveIdleCore(CoreEntry* core) +{ + fIdleCores.Remove(core); + fIdleCoreCount--; + fCoreCount--; + + if (fCoreCount == 0) + gIdlePackageList.Remove(this); +} + + +/* static */ void +DebugDumper::DumpCPURunQueue(CPUEntry* cpu) +{ + ThreadRunQueue::ConstIterator iterator = cpu->fRunQueue.GetConstIterator(); + + if (iterator.HasNext() + && !thread_is_idle_thread(iterator.Next()->GetThread())) { + kprintf("\nCPU %" B_PRId32 " run queue:\n", cpu->ID()); + cpu->fRunQueue.Dump(); + } +} + + +/* static */ void +DebugDumper::DumpCoreRunQueue(CoreEntry* core) +{ + core->fRunQueue.Dump(); +} + + +/* static */ void +DebugDumper::DumpIdleCoresInPackage(PackageEntry* package) +{ + kprintf("%-7" B_PRId32 " ", package->fPackageID); + + DoublyLinkedList::ReverseIterator iterator + = package->fIdleCores.GetReverseIterator(); + if (iterator.HasNext()) { + while (iterator.HasNext()) { + CoreEntry* coreEntry = iterator.Next(); + kprintf("%" B_PRId32 "%s", coreEntry->ID(), + iterator.HasNext() ? ", " : ""); + } + } else + kprintf("-"); + kprintf("\n"); +} + + +static int +dump_run_queue(int /* argc */, char** /* argv */) +{ + int32 cpuCount = smp_get_num_cpus(); + int32 coreCount = gCoreCount; + + for (int32 i = 0; i < coreCount; i++) { + kprintf("%sCore %" B_PRId32 " run queue:\n", i > 0 ? "\n" : "", i); + DebugDumper::DumpCoreRunQueue(&gCoreEntries[i]); + } + + for (int32 i = 0; i < cpuCount; i++) + DebugDumper::DumpCPURunQueue(&gCPUEntries[i]); + + return 0; +} + + +static int +dump_cpu_heap(int /* argc */, char** /* argv */) +{ + kprintf("core load threads\n"); + gCoreLoadHeap.Dump(); + kprintf("\n"); + gCoreHighLoadHeap.Dump(); + + for (int32 i = 0; i < gCoreCount; i++) { + if (gCoreEntries[i].CPUCount() < 2) + continue; + + kprintf("\nCore %" B_PRId32 " heap:\n", i); + gCoreEntries[i].CPUHeap()->Dump(); + } + + return 0; +} + + +static int +dump_idle_cores(int /* argc */, char** /* argv */) +{ + kprintf("Idle packages:\n"); + IdlePackageList::ReverseIterator idleIterator + = gIdlePackageList.GetReverseIterator(); + + if (idleIterator.HasNext()) { + kprintf("package cores\n"); + + while (idleIterator.HasNext()) + DebugDumper::DumpIdleCoresInPackage(idleIterator.Next()); + } else + kprintf("No idle packages.\n"); + + return 0; +} + + +void Scheduler::init_debug_commands() +{ + new(&sDebugCPUHeap) CPUPriorityHeap(smp_get_num_cpus()); + new(&sDebugCoreHeap) CoreLoadHeap(smp_get_num_cpus()); + + add_debugger_command_etc("run_queue", &dump_run_queue, + "List threads in run queue", "\nLists threads in run queue", 0); + if (!gSingleCore) { + add_debugger_command_etc("cpu_heap", &dump_cpu_heap, + "List CPUs in CPU priority heap", + "\nList CPUs in CPU priority heap", 0); + add_debugger_command_etc("idle_cores", &dump_idle_cores, + "List idle cores", "\nList idle cores", 0); + } +} + diff --git a/src/system/kernel/scheduler/scheduler_cpu.h b/src/system/kernel/scheduler/scheduler_cpu.h new file mode 100644 index 0000000000..f8664e7f65 --- /dev/null +++ b/src/system/kernel/scheduler/scheduler_cpu.h @@ -0,0 +1,540 @@ +/* + * Copyright 2013, Paweł Dziepak, pdziepak@quarnos.org. + * Distributed under the terms of the MIT License. + */ +#ifndef KERNEL_SCHEDULER_CPU_H +#define KERNEL_SCHEDULER_CPU_H + + +#include + +#include +#include +#include +#include + +#include + +#include "RunQueue.h" +#include "scheduler_common.h" +#include "scheduler_modes.h" +#include "scheduler_profiler.h" + + +namespace Scheduler { + + +class DebugDumper; + +struct ThreadData; +class ThreadProcessing; + +struct CPUEntry; +struct CoreEntry; +struct PackageEntry; + +// The run queues. Holds the threads ready to run ordered by priority. +// One queue per schedulable target per core. Additionally, each +// logical processor has its sPinnedRunQueues used for scheduling +// pinned threads. +class ThreadRunQueue : public RunQueue { +public: + void Dump() const; +}; + +class CPUEntry : public HeapLinkImpl { +public: + CPUEntry(); + + void Init(int32 id, CoreEntry* core); + + inline int32 ID() const { return fCPUNumber; } + inline CoreEntry* Core() const { return fCore; } + + void Start(); + void Stop(); + + inline void EnterScheduler(); + inline void ExitScheduler(); + + inline void LockScheduler(); + inline void UnlockScheduler(); + + inline void LockRunQueue(); + inline void UnlockRunQueue(); + + void PushFront(ThreadData* thread, + int32 priority); + void PushBack(ThreadData* thread, + int32 priority); + void Remove(ThreadData* thread); + inline ThreadData* PeekThread() const; + ThreadData* PeekIdleThread() const; + + void UpdatePriority(int32 priority); + + inline int32 GetLoad() const { return fLoad; } + void ComputeLoad(); + + ThreadData* ChooseNextThread(ThreadData* oldThread, + bool putAtBack); + + void TrackActivity(ThreadData* oldThreadData, + ThreadData* nextThreadData); + + static inline CPUEntry* GetCPU(int32 cpu); + +private: + void _RequestPerformanceLevel( + ThreadData* threadData); + + int32 fCPUNumber; + CoreEntry* fCore; + + rw_spinlock fSchedulerModeLock; + + ThreadRunQueue fRunQueue; + spinlock fQueueLock; + + int32 fLoad; + + bigtime_t fMeasureActiveTime; + bigtime_t fMeasureTime; + + friend class DebugDumper; +} CACHE_LINE_ALIGN; + +class CPUPriorityHeap : public Heap { +public: + CPUPriorityHeap() { } + CPUPriorityHeap(int32 cpuCount); + + void Dump(); +}; + +class CoreEntry : public MinMaxHeapLinkImpl, + public DoublyLinkedListLinkImpl { +public: + CoreEntry(); + + void Init(int32 id, PackageEntry* package); + + inline int32 ID() const { return fCoreID; } + inline PackageEntry* Package() const { return fPackage; } + inline int32 CPUCount() const + { return fCPUCount; } + + inline void LockCPUHeap(); + inline void UnlockCPUHeap(); + + inline CPUPriorityHeap* CPUHeap(); + + inline int32 ThreadCount() const; + + inline void LockRunQueue(); + inline void UnlockRunQueue(); + + void PushFront(ThreadData* thread, + int32 priority); + void PushBack(ThreadData* thread, + int32 priority); + void Remove(ThreadData* thread); + inline ThreadData* PeekThread() const; + + inline bigtime_t GetActiveTime() const; + inline void IncreaseActiveTime( + bigtime_t activeTime); + + inline int32 GetLoad() const; + void UpdateLoad(int32 delta); + + inline int32 StarvationCounter() const; + inline int32 StarvationCounterIdle() const; + + inline void CPUGoesIdle(CPUEntry* cpu); + inline void CPUWakesUp(CPUEntry* cpu); + + void AddCPU(CPUEntry* cpu); + void RemoveCPU(CPUEntry* cpu, + ThreadProcessing& + threadPostProcessing); + + static inline CoreEntry* GetCore(int32 cpu); + +private: + static void _UnassignThread(Thread* thread, + void* core); + + int32 fCoreID; + PackageEntry* fPackage; + + int32 fCPUCount; + int32 fIdleCPUCount; + CPUPriorityHeap fCPUHeap; + spinlock fCPULock; + + int32 fStarvationCounter; + int32 fStarvationCounterIdle; + + int32 fThreadCount; + ThreadRunQueue fRunQueue; + spinlock fQueueLock; + + bigtime_t fActiveTime; + mutable seqlock fActiveTimeLock; + + int32 fLoad; + bool fHighLoad; + bigtime_t fLastLoadUpdate; + + friend class DebugDumper; +} CACHE_LINE_ALIGN; + +class CoreLoadHeap : public MinMaxHeap { +public: + CoreLoadHeap() { } + CoreLoadHeap(int32 coreCount); + + void Dump(); +}; + +// gPackageEntries are used to decide which core should be woken up from the +// idle state. When aiming for performance we should use as many packages as +// possible with as little cores active in each package as possible (so that the +// package can enter any boost mode if it has one and the active core have more +// of the shared cache for themselves. If power saving is the main priority we +// should keep active cores on as little packages as possible (so that other +// packages can go to the deep state of sleep). The heap stores only packages +// with at least one core active and one core idle. The packages with all cores +// idle are stored in gPackageIdleList (in LIFO manner). +class PackageEntry : public DoublyLinkedListLinkImpl { +public: + PackageEntry(); + + void Init(int32 id); + + inline void CoreGoesIdle(CoreEntry* core); + inline void CoreWakesUp(CoreEntry* core); + + inline CoreEntry* GetIdleCore() const; + + void AddIdleCore(CoreEntry* core); + void RemoveIdleCore(CoreEntry* core); + + static inline PackageEntry* GetMostIdlePackage(); + static inline PackageEntry* GetLeastIdlePackage(); + +private: + int32 fPackageID; + + DoublyLinkedList fIdleCores; + int32 fIdleCoreCount; + int32 fCoreCount; + rw_spinlock fCoreLock; + + friend class DebugDumper; +} CACHE_LINE_ALIGN; +typedef DoublyLinkedList IdlePackageList; + +extern CPUEntry* gCPUEntries; + +extern CoreEntry* gCoreEntries; +extern CoreLoadHeap gCoreLoadHeap; +extern CoreLoadHeap gCoreHighLoadHeap; +extern rw_spinlock gCoreHeapsLock; +extern int32 gCoreCount; + +extern PackageEntry* gPackageEntries; +extern IdlePackageList gIdlePackageList; +extern rw_spinlock gIdlePackageLock; +extern int32 gPackageCount; + + +inline void +CPUEntry::EnterScheduler() +{ + SCHEDULER_ENTER_FUNCTION(); + acquire_read_spinlock(&fSchedulerModeLock); +} + + +inline void +CPUEntry::ExitScheduler() +{ + SCHEDULER_ENTER_FUNCTION(); + release_read_spinlock(&fSchedulerModeLock); +} + + +inline void +CPUEntry::LockScheduler() +{ + SCHEDULER_ENTER_FUNCTION(); + acquire_write_spinlock(&fSchedulerModeLock); +} + + +inline void +CPUEntry::UnlockScheduler() +{ + SCHEDULER_ENTER_FUNCTION(); + release_write_spinlock(&fSchedulerModeLock); +} + + +inline void +CPUEntry::LockRunQueue() +{ + SCHEDULER_ENTER_FUNCTION(); + acquire_spinlock(&fQueueLock); +} + + +inline void +CPUEntry::UnlockRunQueue() +{ + SCHEDULER_ENTER_FUNCTION(); + release_spinlock(&fQueueLock); +} + + +/* static */ inline CPUEntry* +CPUEntry::GetCPU(int32 cpu) +{ + SCHEDULER_ENTER_FUNCTION(); + return &gCPUEntries[cpu]; +} + + +inline void +CoreEntry::LockCPUHeap() +{ + SCHEDULER_ENTER_FUNCTION(); + acquire_spinlock(&fCPULock); +} + + +inline void +CoreEntry::UnlockCPUHeap() +{ + SCHEDULER_ENTER_FUNCTION(); + release_spinlock(&fCPULock); +} + + +inline CPUPriorityHeap* +CoreEntry::CPUHeap() +{ + SCHEDULER_ENTER_FUNCTION(); + return &fCPUHeap; +} + + +inline int32 +CoreEntry::ThreadCount() const +{ + SCHEDULER_ENTER_FUNCTION(); + return fThreadCount + fCPUCount - fIdleCPUCount; +} + + +inline void +CoreEntry::LockRunQueue() +{ + SCHEDULER_ENTER_FUNCTION(); + acquire_spinlock(&fQueueLock); +} + + +inline void +CoreEntry::UnlockRunQueue() +{ + SCHEDULER_ENTER_FUNCTION(); + release_spinlock(&fQueueLock); +} + + +inline void +CoreEntry::IncreaseActiveTime(bigtime_t activeTime) +{ + SCHEDULER_ENTER_FUNCTION(); + WriteSequentialLocker _(fActiveTimeLock); + fActiveTime += activeTime; +} + + +inline bigtime_t +CoreEntry::GetActiveTime() const +{ + SCHEDULER_ENTER_FUNCTION(); + + bigtime_t activeTime; + uint32 count; + do { + count = acquire_read_seqlock(&fActiveTimeLock); + activeTime = fActiveTime; + } while (!release_read_seqlock(&fActiveTimeLock, count)); + return activeTime; +} + + +inline int32 +CoreEntry::GetLoad() const +{ + SCHEDULER_ENTER_FUNCTION(); + + ASSERT(fCPUCount > 0); + return fLoad / fCPUCount; +} + + +inline int32 +CoreEntry::StarvationCounter() const +{ + SCHEDULER_ENTER_FUNCTION(); + return fStarvationCounter; +} + + +inline int32 +CoreEntry::StarvationCounterIdle() const +{ + SCHEDULER_ENTER_FUNCTION(); + return fStarvationCounterIdle; +} + + +/* PackageEntry::CoreGoesIdle and PackageEntry::CoreWakesUp have to be defined + before CoreEntry::CPUGoesIdle and CoreEntry::CPUWakesUp. If they weren't + GCC2 wouldn't inline them as, apparently, it doesn't do enough optimization + passes. +*/ +inline void +PackageEntry::CoreGoesIdle(CoreEntry* core) +{ + SCHEDULER_ENTER_FUNCTION(); + + WriteSpinLocker _(fCoreLock); + + ASSERT(fIdleCoreCount >= 0); + ASSERT(fIdleCoreCount < fCoreCount); + + fIdleCoreCount++; + fIdleCores.Add(core); + + if (fIdleCoreCount == fCoreCount) { + // package goes idle + WriteSpinLocker _(gIdlePackageLock); + gIdlePackageList.Add(this); + } +} + + +inline void +PackageEntry::CoreWakesUp(CoreEntry* core) +{ + SCHEDULER_ENTER_FUNCTION(); + + WriteSpinLocker _(fCoreLock); + + ASSERT(fIdleCoreCount > 0); + ASSERT(fIdleCoreCount <= fCoreCount); + + fIdleCoreCount--; + fIdleCores.Remove(core); + + if (fIdleCoreCount + 1 == fCoreCount) { + // package wakes up + WriteSpinLocker _(gIdlePackageLock); + gIdlePackageList.Remove(this); + } +} + + +inline void +CoreEntry::CPUGoesIdle(CPUEntry* /* cpu */) +{ + atomic_add(&fStarvationCounter, 1); + atomic_add(&fStarvationCounterIdle, 1); + + if (gSingleCore) + return; + + ASSERT(fIdleCPUCount < fCPUCount); + if (++fIdleCPUCount == fCPUCount) + fPackage->CoreGoesIdle(this); +} + + +inline void +CoreEntry::CPUWakesUp(CPUEntry* /* cpu */) +{ + if (gSingleCore) + return; + + ASSERT(fIdleCPUCount > 0); + if (fIdleCPUCount-- == fCPUCount) + fPackage->CoreWakesUp(this); +} + + +/* static */ inline CoreEntry* +CoreEntry::GetCore(int32 cpu) +{ + SCHEDULER_ENTER_FUNCTION(); + return gCPUEntries[cpu].Core(); +} + + +inline CoreEntry* +PackageEntry::GetIdleCore() const +{ + SCHEDULER_ENTER_FUNCTION(); + return fIdleCores.Last(); +} + + +/* static */ inline PackageEntry* +PackageEntry::GetMostIdlePackage() +{ + SCHEDULER_ENTER_FUNCTION(); + + PackageEntry* current = &gPackageEntries[0]; + for (int32 i = 1; i < gPackageCount; i++) { + if (gPackageEntries[i].fIdleCoreCount > current->fIdleCoreCount) + current = &gPackageEntries[i]; + } + + if (current->fIdleCoreCount == 0) + return NULL; + + return current; +} + + +/* static */ inline PackageEntry* +PackageEntry::GetLeastIdlePackage() +{ + SCHEDULER_ENTER_FUNCTION(); + + PackageEntry* package = NULL; + + for (int32 i = 0; i < gPackageCount; i++) { + PackageEntry* current = &gPackageEntries[i]; + + int32 currentIdleCoreCount = current->fIdleCoreCount; + if (currentIdleCoreCount != 0 && (package == NULL + || currentIdleCoreCount < package->fIdleCoreCount)) { + package = current; + } + } + + return package; +} + + +} // namespace Scheduler + + +#endif // KERNEL_SCHEDULER_CPU_H + diff --git a/src/system/kernel/scheduler/scheduler_locking.h b/src/system/kernel/scheduler/scheduler_locking.h new file mode 100644 index 0000000000..8feffe60ed --- /dev/null +++ b/src/system/kernel/scheduler/scheduler_locking.h @@ -0,0 +1,161 @@ +/* + * Copyright 2014, Paweł Dziepak, pdziepak@quarnos.org. + * Distributed under the terms of the MIT License. + */ +#ifndef KERNEL_SCHEDULER_LOCKING_H +#define KERNEL_SCHEDULER_LOCKING_H + + +#include + +#include "scheduler_cpu.h" + + +namespace Scheduler { + + +class CPURunQueueLocking { +public: + inline bool Lock(CPUEntry* cpu) + { + cpu->LockRunQueue(); + return true; + } + + inline void Unlock(CPUEntry* cpu) + { + cpu->UnlockRunQueue(); + } +}; + +typedef AutoLocker CPURunQueueLocker; + + +class CoreRunQueueLocking { +public: + inline bool Lock(CoreEntry* core) + { + core->LockRunQueue(); + return true; + } + + inline void Unlock(CoreEntry* core) + { + core->UnlockRunQueue(); + } +}; + +typedef AutoLocker CoreRunQueueLocker; + +class CoreCPUHeapLocking { +public: + inline bool Lock(CoreEntry* core) + { + core->LockCPUHeap(); + return true; + } + + inline void Unlock(CoreEntry* core) + { + core->UnlockCPUHeap(); + } +}; + +typedef AutoLocker CoreCPUHeapLocker; + +class SchedulerModeLocking { +public: + bool Lock(int* /* lockable */) + { + CPUEntry::GetCPU(smp_get_current_cpu())->EnterScheduler(); + return true; + } + + void Unlock(int* /* lockable */) + { + CPUEntry::GetCPU(smp_get_current_cpu())->ExitScheduler(); + } +}; + +class SchedulerModeLocker : + public AutoLocker { +public: + SchedulerModeLocker(bool alreadyLocked = false, bool lockIfNotLocked = true) + : + AutoLocker(&fDummy, alreadyLocked, + lockIfNotLocked) + { + } + +private: + int fDummy; +}; + +class InterruptsSchedulerModeLocking { +public: + bool Lock(int* lockable) + { + *lockable = disable_interrupts(); + CPUEntry::GetCPU(smp_get_current_cpu())->EnterScheduler(); + return true; + } + + void Unlock(int* lockable) + { + CPUEntry::GetCPU(smp_get_current_cpu())->ExitScheduler(); + restore_interrupts(*lockable); + } +}; + +class InterruptsSchedulerModeLocker : + public AutoLocker { +public: + InterruptsSchedulerModeLocker(bool alreadyLocked = false, + bool lockIfNotLocked = true) + : + AutoLocker(&fState, alreadyLocked, + lockIfNotLocked) + { + } + +private: + int fState; +}; + +class InterruptsBigSchedulerLocking { +public: + bool Lock(int* lockable) + { + *lockable = disable_interrupts(); + for (int32 i = 0; i < smp_get_num_cpus(); i++) + CPUEntry::GetCPU(i)->LockScheduler(); + return true; + } + + void Unlock(int* lockable) + { + for (int32 i = 0; i < smp_get_num_cpus(); i++) + CPUEntry::GetCPU(i)->UnlockScheduler(); + restore_interrupts(*lockable); + } +}; + +class InterruptsBigSchedulerLocker : + public AutoLocker { +public: + InterruptsBigSchedulerLocker() + : + AutoLocker(&fState, false, true) + { + } + +private: + int fState; +}; + + +} // namespace Scheduler + + +#endif // KERNEL_SCHEDULER_LOCKING_H + diff --git a/src/system/kernel/scheduler/scheduler_modes.h b/src/system/kernel/scheduler/scheduler_modes.h new file mode 100644 index 0000000000..820912afd9 --- /dev/null +++ b/src/system/kernel/scheduler/scheduler_modes.h @@ -0,0 +1,48 @@ +/* + * Copyright 2013, Paweł Dziepak, pdziepak@quarnos.org. + * Distributed under the terms of the MIT License. + */ +#ifndef KERNEL_SCHEDULER_MODES_H +#define KERNEL_SCHEDULER_MODES_H + + +#include +#include + + +struct scheduler_mode_operations { + const char* name; + + bigtime_t base_quantum; + bigtime_t minimal_quantum; + bigtime_t quantum_multipliers[2]; + + bigtime_t maximum_latency; + + void (*switch_to_mode)(); + void (*set_cpu_enabled)(int32 cpu, bool enabled); + bool (*has_cache_expired)( + const Scheduler::ThreadData* threadData); + Scheduler::CoreEntry* (*choose_core)( + const Scheduler::ThreadData* threadData); + bool (*should_rebalance)( + const Scheduler::ThreadData* threadData); + void (*rebalance_irqs)(bool idle); +}; + +extern struct scheduler_mode_operations gSchedulerLowLatencyMode; +extern struct scheduler_mode_operations gSchedulerPowerSavingMode; + + +namespace Scheduler { + + +extern scheduler_mode gCurrentModeID; +extern scheduler_mode_operations* gCurrentMode; + + +} + + +#endif // KERNEL_SCHEDULER_MODES_H + diff --git a/src/system/kernel/scheduler/scheduler_profiler.cpp b/src/system/kernel/scheduler/scheduler_profiler.cpp new file mode 100644 index 0000000000..d3399de78b --- /dev/null +++ b/src/system/kernel/scheduler/scheduler_profiler.cpp @@ -0,0 +1,323 @@ +/* + * Copyright 2013, Paweł Dziepak, pdziepak@quarnos.org. + * Distributed under the terms of the MIT License. + */ + +#include "scheduler_profiler.h" + +#include +#include + +#include + + +#ifdef SCHEDULER_PROFILING + + +using namespace Scheduler; +using namespace Scheduler::Profiling; + + +static Profiler* sProfiler; + +static int dump_profiler(int argc, char** argv); + + +Profiler::Profiler() + : + kMaxFunctionEntries(1024), + kMaxFunctionStackEntries(512), + fFunctionData(new(std::nothrow) FunctionData[kMaxFunctionEntries]), + fStatus(B_OK) +{ + B_INITIALIZE_SPINLOCK(&fFunctionLock); + + if (fFunctionData == NULL) { + fStatus = B_NO_MEMORY; + return; + } + memset(fFunctionData, 0, sizeof(FunctionData) * kMaxFunctionEntries); + + for (int32 i = 0; i < smp_get_num_cpus(); i++) { + fFunctionStacks[i] + = new(std::nothrow) FunctionEntry[kMaxFunctionStackEntries]; + if (fFunctionStacks[i] == NULL) { + fStatus = B_NO_MEMORY; + return; + } + memset(fFunctionStacks[i], 0, + sizeof(FunctionEntry) * kMaxFunctionStackEntries); + } + memset(fFunctionStackPointers, 0, sizeof(int32) * smp_get_num_cpus()); +} + + +void +Profiler::EnterFunction(int32 cpu, const char* functionName) +{ + nanotime_t start = system_time_nsecs(); + + FunctionData* function = _FindFunction(functionName); + if (function == NULL) + return; + atomic_add((int32*)&function->fCalled, 1); + + FunctionEntry* stackEntry + = &fFunctionStacks[cpu][fFunctionStackPointers[cpu]]; + fFunctionStackPointers[cpu]++; + + ASSERT(fFunctionStackPointers[cpu] < kMaxFunctionStackEntries); + + stackEntry->fFunction = function; + stackEntry->fEntryTime = start; + stackEntry->fOthersTime = 0; + + nanotime_t stop = system_time_nsecs(); + stackEntry->fProfilerTime = stop - start; +} + + +void +Profiler::ExitFunction(int32 cpu, const char* functionName) +{ + nanotime_t start = system_time_nsecs(); + + ASSERT(fFunctionStackPointers[cpu] > 0); + fFunctionStackPointers[cpu]--; + FunctionEntry* stackEntry + = &fFunctionStacks[cpu][fFunctionStackPointers[cpu]]; + + nanotime_t timeSpent = start - stackEntry->fEntryTime; + timeSpent -= stackEntry->fProfilerTime; + + atomic_add64(&stackEntry->fFunction->fTimeInclusive, timeSpent); + atomic_add64(&stackEntry->fFunction->fTimeExclusive, + timeSpent - stackEntry->fOthersTime); + + nanotime_t profilerTime = stackEntry->fProfilerTime; + if (fFunctionStackPointers[cpu] > 0) { + stackEntry = &fFunctionStacks[cpu][fFunctionStackPointers[cpu] - 1]; + stackEntry->fOthersTime += timeSpent; + stackEntry->fProfilerTime += profilerTime; + + nanotime_t stop = system_time_nsecs(); + stackEntry->fProfilerTime += stop - start; + } +} + + +void +Profiler::DumpCalled(uint32 maxCount) +{ + uint32 count = _FunctionCount(); + + qsort(fFunctionData, count, sizeof(FunctionData), + &_CompareFunctions); + + if (maxCount > 0) + count = std::min(count, maxCount); + _Dump(count); +} + + +void +Profiler::DumpTimeInclusive(uint32 maxCount) +{ + uint32 count = _FunctionCount(); + + qsort(fFunctionData, count, sizeof(FunctionData), + &_CompareFunctions); + + if (maxCount > 0) + count = std::min(count, maxCount); + _Dump(count); +} + + +void +Profiler::DumpTimeExclusive(uint32 maxCount) +{ + uint32 count = _FunctionCount(); + + qsort(fFunctionData, count, sizeof(FunctionData), + &_CompareFunctions); + + if (maxCount > 0) + count = std::min(count, maxCount); + _Dump(count); +} + + +void +Profiler::DumpTimeInclusivePerCall(uint32 maxCount) +{ + uint32 count = _FunctionCount(); + + qsort(fFunctionData, count, sizeof(FunctionData), + &_CompareFunctionsPerCall); + + if (maxCount > 0) + count = std::min(count, maxCount); + _Dump(count); +} + + +void +Profiler::DumpTimeExclusivePerCall(uint32 maxCount) +{ + uint32 count = _FunctionCount(); + + qsort(fFunctionData, count, sizeof(FunctionData), + &_CompareFunctionsPerCall); + + if (maxCount > 0) + count = std::min(count, maxCount); + _Dump(count); +} + + +/* static */ Profiler* +Profiler::Get() +{ + return sProfiler; +} + + +/* static */ void +Profiler::Initialize() +{ + sProfiler = new(std::nothrow) Profiler; + if (sProfiler == NULL || sProfiler->GetStatus() != B_OK) + panic("Scheduler::Profiling::Profiler: could not initialize profiler"); + + add_debugger_command_etc("scheduler_profiler", &dump_profiler, + "Show data collected by scheduler profiler", + "[ [ ] ]\n" + "Shows data collected by scheduler profiler\n" + " - Field used to sort functions. Available: called," + " time-inclusive, time-inclusive-per-call, time-exclusive," + " time-exclusive-per-call.\n" + " (defaults to \"called\")\n" + " - Maximum number of showed functions.\n", 0); +} + + +uint32 +Profiler::_FunctionCount() const +{ + uint32 count; + for (count = 0; count < kMaxFunctionEntries; count++) { + if (fFunctionData[count].fFunction == NULL) + break; + } + return count; +} + + +void +Profiler::_Dump(uint32 count) +{ + kprintf("Function calls (%" B_PRId32 " functions):\n", count); + kprintf(" called time-inclusive per-call time-exclusive per-call " + "function\n"); + for (uint32 i = 0; i < count; i++) { + FunctionData* function = &fFunctionData[i]; + kprintf("%10" B_PRId32 " %14" B_PRId64 " %8" B_PRId64 " %14" B_PRId64 + " %8" B_PRId64 " %s\n", function->fCalled, + function->fTimeInclusive, + function->fTimeInclusive / function->fCalled, + function->fTimeExclusive, + function->fTimeExclusive / function->fCalled, function->fFunction); + } +} + + +Profiler::FunctionData* +Profiler::_FindFunction(const char* function) +{ + for (uint32 i = 0; i < kMaxFunctionEntries; i++) { + if (fFunctionData[i].fFunction == NULL) + break; + if (!strcmp(fFunctionData[i].fFunction, function)) + return fFunctionData + i; + } + + SpinLocker _(fFunctionLock); + for (uint32 i = 0; i < kMaxFunctionEntries; i++) { + if (fFunctionData[i].fFunction == NULL) { + fFunctionData[i].fFunction = function; + return fFunctionData + i; + } + if (!strcmp(fFunctionData[i].fFunction, function)) + return fFunctionData + i; + } + + return NULL; +} + + +template +/* static */ int +Profiler::_CompareFunctions(const void* _a, const void* _b) +{ + const FunctionData* a = static_cast(_a); + const FunctionData* b = static_cast(_b); + + if (b->*Member > a->*Member) + return 1; + if (b->*Member < a->*Member) + return -1; + return 0; +} + + +template +/* static */ int +Profiler::_CompareFunctionsPerCall(const void* _a, const void* _b) +{ + const FunctionData* a = static_cast(_a); + const FunctionData* b = static_cast(_b); + + Type valueA = a->*Member / a->fCalled; + Type valueB = b->*Member / b->fCalled; + + if (valueB > valueA) + return 1; + if (valueB < valueA) + return -1; + return 0; +} + + +static int +dump_profiler(int argc, char** argv) +{ + if (argc < 2) { + Profiler::Get()->DumpCalled(0); + return 0; + } + + int32 count = 0; + if (argc >= 3) + count = parse_expression(argv[2]); + count = std::max(count, int32(0)); + + if (!strcmp(argv[1], "called")) + Profiler::Get()->DumpCalled(count); + else if (!strcmp(argv[1], "time-inclusive")) + Profiler::Get()->DumpTimeInclusive(count); + else if (!strcmp(argv[1], "time-inclusive-per-call")) + Profiler::Get()->DumpTimeInclusivePerCall(count); + else if (!strcmp(argv[1], "time-exclusive")) + Profiler::Get()->DumpTimeExclusive(count); + else if (!strcmp(argv[1], "time-exclusive-per-call")) + Profiler::Get()->DumpTimeExclusivePerCall(count); + else + print_debugger_command_usage(argv[0]); + + return 0; +} + + +#endif // SCHEDULER_PROFILING + diff --git a/src/system/kernel/scheduler/scheduler_profiler.h b/src/system/kernel/scheduler/scheduler_profiler.h new file mode 100644 index 0000000000..d2c1bfca3d --- /dev/null +++ b/src/system/kernel/scheduler/scheduler_profiler.h @@ -0,0 +1,136 @@ +/* + * Copyright 2013, Paweł Dziepak, pdziepak@quarnos.org. + * Distributed under the terms of the MIT License. + */ +#ifndef KERNEL_SCHEDULER_PROFILER_H +#define KERNEL_SCHEDULER_PROFILER_H + + +#include + + +//#define SCHEDULER_PROFILING +#ifdef SCHEDULER_PROFILING + + +#define SCHEDULER_ENTER_FUNCTION() \ + Scheduler::Profiling::Function schedulerProfiler(__PRETTY_FUNCTION__) + +#define SCHEDULER_EXIT_FUNCTION() \ + schedulerProfiler.Exit() + + +namespace Scheduler { + +namespace Profiling { + +class Profiler { +public: + Profiler(); + + void EnterFunction(int32 cpu, const char* function); + void ExitFunction(int32 cpu, const char* function); + + void DumpCalled(uint32 count); + void DumpTimeInclusive(uint32 count); + void DumpTimeExclusive(uint32 count); + void DumpTimeInclusivePerCall(uint32 count); + void DumpTimeExclusivePerCall(uint32 count); + + status_t GetStatus() const { return fStatus; } + + static Profiler* Get(); + static void Initialize(); + +private: + struct FunctionData { + const char* fFunction; + + uint32 fCalled; + + bigtime_t fTimeInclusive; + bigtime_t fTimeExclusive; + }; + + struct FunctionEntry { + FunctionData* fFunction; + + nanotime_t fEntryTime; + nanotime_t fOthersTime; + nanotime_t fProfilerTime; + }; + + uint32 _FunctionCount() const; + void _Dump(uint32 count); + + FunctionData* _FindFunction(const char* function); + + template + static int _CompareFunctions(const void* a, const void* b); + + template + static int _CompareFunctionsPerCall(const void* a, + const void* b); + + const uint32 kMaxFunctionEntries; + const uint32 kMaxFunctionStackEntries; + + FunctionEntry* fFunctionStacks[SMP_MAX_CPUS]; + uint32 fFunctionStackPointers[SMP_MAX_CPUS]; + + FunctionData* fFunctionData; + spinlock fFunctionLock; + + status_t fStatus; +}; + +class Function { +public: + inline Function(const char* functionName); + inline ~Function(); + + inline void Exit(); + +private: + const char* fFunctionName; +}; + + +Function::Function(const char* functionName) + : + fFunctionName(functionName) +{ + Profiler::Get()->EnterFunction(smp_get_current_cpu(), fFunctionName); +} + + +Function::~Function() +{ + if (fFunctionName != NULL) + Exit(); +} + + +void +Function::Exit() +{ + Profiler::Get()->ExitFunction(smp_get_current_cpu(), fFunctionName); + fFunctionName = NULL; +} + + +} // namespace Profiling + +} // namespace Scheduler + + +#else // SCHEDULER_PROFILING + +#define SCHEDULER_ENTER_FUNCTION() (void)0 +#define SCHEDULER_EXIT_FUNCTION() (void)0 + +#endif // !SCHEDULER_PROFILING + + +#endif // KERNEL_SCHEDULER_PROFILER_H + diff --git a/src/system/kernel/scheduler/scheduler_simple.cpp b/src/system/kernel/scheduler/scheduler_simple.cpp deleted file mode 100644 index 6b60d3ca0c..0000000000 --- a/src/system/kernel/scheduler/scheduler_simple.cpp +++ /dev/null @@ -1,382 +0,0 @@ -/* - * Copyright 2008-2011, Ingo Weinhold, ingo_weinhold@gmx.de. - * Copyright 2002-2010, Axel Dörfler, axeld@pinc-software.de. - * Copyright 2002, Angelo Mottola, a.mottola@libero.it. - * Distributed under the terms of the MIT License. - * - * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. - * Distributed under the terms of the NewOS License. - */ - - -/*! The thread scheduler */ - - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "scheduler_common.h" -#include "scheduler_tracing.h" - - -//#define TRACE_SCHEDULER -#ifdef TRACE_SCHEDULER -# define TRACE(x) dprintf_no_syslog x -#else -# define TRACE(x) ; -#endif - - -const bigtime_t kThreadQuantum = 3000; - - -// The run queue. Holds the threads ready to run ordered by priority. -static Thread *sRunQueue = NULL; - - -static int -dump_run_queue(int argc, char **argv) -{ - Thread *thread; - - thread = sRunQueue; - if (!thread) - kprintf("Run queue is empty!\n"); - else { - kprintf("thread id priority name\n"); - while (thread) { - kprintf("%p %-7" B_PRId32 " %-8" B_PRId32 " %s\n", thread, - thread->id, thread->priority, thread->name); - thread = thread->queue_next; - } - } - - return 0; -} - - -/*! Enqueues the thread into the run queue. - Note: thread lock must be held when entering this function -*/ -static void -simple_enqueue_in_run_queue(Thread *thread) -{ - thread->state = thread->next_state = B_THREAD_READY; - - Thread *curr, *prev; - for (curr = sRunQueue, prev = NULL; curr - && curr->priority >= thread->next_priority; - curr = curr->queue_next) { - if (prev) - prev = prev->queue_next; - else - prev = sRunQueue; - } - - T(EnqueueThread(thread, prev, curr)); - - thread->queue_next = curr; - if (prev) - prev->queue_next = thread; - else - sRunQueue = thread; - - thread->next_priority = thread->priority; - - // notify listeners - NotifySchedulerListeners(&SchedulerListener::ThreadEnqueuedInRunQueue, - thread); - - if (thread->priority > thread_get_current_thread()->priority) { - gCPU[0].invoke_scheduler = true; - gCPU[0].invoke_scheduler_if_idle = false; - } -} - - -/*! Sets the priority of a thread. - Note: thread lock must be held when entering this function -*/ -static void -simple_set_thread_priority(Thread *thread, int32 priority) -{ - if (priority == thread->priority) - return; - - if (thread->state != B_THREAD_READY) { - thread->priority = priority; - return; - } - - // The thread is in the run queue. We need to remove it and re-insert it at - // a new position. - - T(RemoveThread(thread)); - - // notify listeners - NotifySchedulerListeners(&SchedulerListener::ThreadRemovedFromRunQueue, - thread); - - // find thread in run queue - Thread *item, *prev; - for (item = sRunQueue, prev = NULL; item && item != thread; - item = item->queue_next) { - if (prev) - prev = prev->queue_next; - else - prev = sRunQueue; - } - - ASSERT(item == thread); - - // remove the thread - if (prev) - prev->queue_next = item->queue_next; - else - sRunQueue = item->queue_next; - - // set priority and re-insert - thread->priority = thread->next_priority = priority; - simple_enqueue_in_run_queue(thread); -} - - -static bigtime_t -simple_estimate_max_scheduling_latency(Thread* thread) -{ - // TODO: This is probably meant to be called periodically to return the - // current estimate depending on the system usage; we return fixed estimates - // per thread priority, though. - - if (thread->priority >= B_REAL_TIME_DISPLAY_PRIORITY) - return kThreadQuantum / 4; - if (thread->priority >= B_DISPLAY_PRIORITY) - return kThreadQuantum; - - return 2 * kThreadQuantum; -} - - -static int32 -reschedule_event(timer *unused) -{ - // This function is called as a result of the timer event set by the - // scheduler. Make sure the reschedule() is invoked. - thread_get_current_thread()->cpu->invoke_scheduler = true; - thread_get_current_thread()->cpu->invoke_scheduler_if_idle = false; - thread_get_current_thread()->cpu->preempted = 1; - return B_HANDLED_INTERRUPT; -} - - -/*! Runs the scheduler. - Note: expects thread spinlock to be held -*/ -static void -simple_reschedule(void) -{ - Thread *oldThread = thread_get_current_thread(); - Thread *nextThread, *prevThread; - - // check whether we're only supposed to reschedule, if the current thread - // is idle - if (oldThread->cpu->invoke_scheduler) { - oldThread->cpu->invoke_scheduler = false; - if (oldThread->cpu->invoke_scheduler_if_idle - && oldThread->priority != B_IDLE_PRIORITY) { - oldThread->cpu->invoke_scheduler_if_idle = false; - return; - } - } - - TRACE(("reschedule(): current thread = %ld\n", oldThread->id)); - - oldThread->state = oldThread->next_state; - switch (oldThread->next_state) { - case B_THREAD_RUNNING: - case B_THREAD_READY: - TRACE(("enqueueing thread %ld into run queue priority = %ld\n", - oldThread->id, oldThread->priority)); - simple_enqueue_in_run_queue(oldThread); - break; - case B_THREAD_SUSPENDED: - TRACE(("reschedule(): suspending thread %ld\n", oldThread->id)); - break; - case THREAD_STATE_FREE_ON_RESCHED: - break; - default: - TRACE(("not enqueueing thread %ld into run queue next_state = %ld\n", - oldThread->id, oldThread->next_state)); - break; - } - - nextThread = sRunQueue; - prevThread = NULL; - - while (nextThread) { - // select next thread from the run queue - while (nextThread && nextThread->priority > B_IDLE_PRIORITY) { -#if 0 - if (oldThread == nextThread && nextThread->was_yielded) { - // ignore threads that called thread_yield() once - nextThread->was_yielded = false; - prevThread = nextThread; - nextThread = nextThread->queue_next; - } -#endif - - // always extract real time threads - if (nextThread->priority >= B_FIRST_REAL_TIME_PRIORITY) - break; - - // find next thread with lower priority - Thread *lowerNextThread = nextThread->queue_next; - Thread *lowerPrevThread = nextThread; - int32 priority = nextThread->priority; - - while (lowerNextThread != NULL - && priority == lowerNextThread->priority) { - lowerPrevThread = lowerNextThread; - lowerNextThread = lowerNextThread->queue_next; - } - // never skip last non-idle normal thread - if (lowerNextThread == NULL - || lowerNextThread->priority == B_IDLE_PRIORITY) - break; - - int32 priorityDiff = priority - lowerNextThread->priority; - if (priorityDiff > 15) - break; - - // skip normal threads sometimes - // (twice as probable per priority level) - if ((fast_random_value() >> (15 - priorityDiff)) != 0) - break; - - nextThread = lowerNextThread; - prevThread = lowerPrevThread; - } - - break; - } - - if (!nextThread) - panic("reschedule(): run queue is empty!\n"); - - // extract selected thread from the run queue - if (prevThread) - prevThread->queue_next = nextThread->queue_next; - else - sRunQueue = nextThread->queue_next; - - T(ScheduleThread(nextThread, oldThread)); - - // notify listeners - NotifySchedulerListeners(&SchedulerListener::ThreadScheduled, - oldThread, nextThread); - - nextThread->state = B_THREAD_RUNNING; - nextThread->next_state = B_THREAD_READY; - oldThread->was_yielded = false; - - // track kernel time (user time is tracked in thread_at_kernel_entry()) - scheduler_update_thread_times(oldThread, nextThread); - - // track CPU activity - if (!thread_is_idle_thread(oldThread)) { - oldThread->cpu->active_time += - (oldThread->kernel_time - oldThread->cpu->last_kernel_time) - + (oldThread->user_time - oldThread->cpu->last_user_time); - } - - if (!thread_is_idle_thread(nextThread)) { - oldThread->cpu->last_kernel_time = nextThread->kernel_time; - oldThread->cpu->last_user_time = nextThread->user_time; - } - - if (nextThread != oldThread || oldThread->cpu->preempted) { - bigtime_t quantum = kThreadQuantum; // TODO: calculate quantum? - timer* quantumTimer = &oldThread->cpu->quantum_timer; - - if (!oldThread->cpu->preempted) - cancel_timer(quantumTimer); - - oldThread->cpu->preempted = 0; - if (!thread_is_idle_thread(nextThread)) { - add_timer(quantumTimer, &reschedule_event, quantum, - B_ONE_SHOT_RELATIVE_TIMER | B_TIMER_ACQUIRE_SCHEDULER_LOCK); - } - - if (nextThread != oldThread) - scheduler_switch_thread(oldThread, nextThread); - } -} - - -static status_t -simple_on_thread_create(Thread* thread, bool idleThread) -{ - // do nothing - return B_OK; -} - - -static void -simple_on_thread_init(Thread* thread) -{ - // do nothing -} - - -static void -simple_on_thread_destroy(Thread* thread) -{ - // do nothing -} - - -/*! This starts the scheduler. Must be run in the context of the initial idle - thread. Interrupts must be disabled and will be disabled when returning. -*/ -static void -simple_start(void) -{ - SpinLocker schedulerLocker(gSchedulerLock); - - simple_reschedule(); -} - - -static scheduler_ops kSimpleOps = { - simple_enqueue_in_run_queue, - simple_reschedule, - simple_set_thread_priority, - simple_estimate_max_scheduling_latency, - simple_on_thread_create, - simple_on_thread_init, - simple_on_thread_destroy, - simple_start -}; - - -// #pragma mark - - - -void -scheduler_simple_init() -{ - gScheduler = &kSimpleOps; - - add_debugger_command_etc("run_queue", &dump_run_queue, - "List threads in run queue", "\nLists threads in run queue", 0); -} diff --git a/src/system/kernel/scheduler/scheduler_simple.h b/src/system/kernel/scheduler/scheduler_simple.h deleted file mode 100644 index bac69ac78c..0000000000 --- a/src/system/kernel/scheduler/scheduler_simple.h +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de. - * Distributed under the terms of the MIT License. - */ -#ifndef KERNEL_SCHEDULER_SIMPLE_H -#define KERNEL_SCHEDULER_SIMPLE_H - - -void scheduler_simple_init(); - - -#endif // KERNEL_SCHEDULER_SIMPLE_H diff --git a/src/system/kernel/scheduler/scheduler_simple_smp.cpp b/src/system/kernel/scheduler/scheduler_simple_smp.cpp deleted file mode 100644 index c4d1e8a2df..0000000000 --- a/src/system/kernel/scheduler/scheduler_simple_smp.cpp +++ /dev/null @@ -1,483 +0,0 @@ -/* - * Copyright 2008-2011, Ingo Weinhold, ingo_weinhold@gmx.de. - * Copyright 2002-2010, Axel Dörfler, axeld@pinc-software.de. - * Copyright 2002, Angelo Mottola, a.mottola@libero.it. - * Distributed under the terms of the MIT License. - * - * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. - * Distributed under the terms of the NewOS License. - */ - - -/*! The thread scheduler */ - - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "scheduler_common.h" -#include "scheduler_tracing.h" - - -//#define TRACE_SCHEDULER -#ifdef TRACE_SCHEDULER -# define TRACE(x) dprintf_no_syslog x -#else -# define TRACE(x) ; -#endif - - -const bigtime_t kThreadQuantum = 3000; - - -// The run queue. Holds the threads ready to run ordered by priority. -static Thread *sRunQueue = NULL; -static int32 sCPUCount = 1; -static int32 sNextCPUForSelection = 0; - - -static int -dump_run_queue(int argc, char **argv) -{ - Thread *thread; - - thread = sRunQueue; - if (!thread) - kprintf("Run queue is empty!\n"); - else { - kprintf("thread id priority name\n"); - while (thread) { - kprintf("%p %-7" B_PRId32 " %-8" B_PRId32 " %s\n", thread, - thread->id, thread->priority, thread->name); - thread = thread->queue_next; - } - } - - return 0; -} - - -static int32 -select_cpu(int32 currentCPU, Thread* thread, int32& targetPriority) -{ - if (thread->pinned_to_cpu > 0) { - // the thread is pinned to a specific CPU - int32 targetCPU = thread->previous_cpu->cpu_num; - targetPriority = gCPU[targetCPU].running_thread->priority; - return targetCPU; - } - - // Choose the CPU running the lowest priority thread. Favor the current CPU - // as it doesn't require ICI to be notified. - int32 targetCPU = currentCPU; - targetPriority = B_IDLE_PRIORITY; - if (gCPU[currentCPU].disabled) - targetCPU = -1; - else - targetPriority = gCPU[currentCPU].running_thread->priority; - - int32 cpu = sNextCPUForSelection; - for (int32 i = 0; i < sCPUCount; i++, cpu++) { - if (cpu >= sCPUCount) - cpu = 0; - - if (!gCPU[cpu].disabled) { - int32 cpuPriority = gCPU[cpu].running_thread->priority; - if (targetCPU < 0 || cpuPriority < targetPriority) { - targetCPU = cpu; - targetPriority = cpuPriority; - } - } - } - - if (++sNextCPUForSelection >= sCPUCount) - sNextCPUForSelection = 0; - - return targetCPU; -} - - -/*! Enqueues the thread into the run queue. - Note: thread lock must be held when entering this function -*/ -static void -enqueue_in_run_queue(Thread *thread) -{ - thread->state = thread->next_state = B_THREAD_READY; - - Thread *curr, *prev; - for (curr = sRunQueue, prev = NULL; curr - && curr->priority >= thread->next_priority; - curr = curr->queue_next) { - if (prev) - prev = prev->queue_next; - else - prev = sRunQueue; - } - - T(EnqueueThread(thread, prev, curr)); - - thread->queue_next = curr; - if (prev) - prev->queue_next = thread; - else - sRunQueue = thread; - - thread->next_priority = thread->priority; - - if (thread->priority != B_IDLE_PRIORITY) { - // Select a CPU for the thread to run on. It's not certain that the - // thread will actually run on it, but we will notify the CPU to - // preempt the thread it is currently running, if the new thread has - // a higher priority. - int32 currentCPU = smp_get_current_cpu(); - int32 targetPriority; - int32 targetCPU = select_cpu(currentCPU, thread, targetPriority); - - // If the target CPU runs a thread with a lower priority, tell it to - // reschedule. - if (thread->priority > targetPriority) { - if (targetCPU == currentCPU) { - gCPU[targetCPU].invoke_scheduler = true; - gCPU[targetCPU].invoke_scheduler_if_idle = false; - } else { - if (targetPriority == B_IDLE_PRIORITY) { - smp_send_ici(targetCPU, SMP_MSG_RESCHEDULE_IF_IDLE, 0, 0, - 0, NULL, SMP_MSG_FLAG_ASYNC); - } else { - smp_send_ici(targetCPU, SMP_MSG_RESCHEDULE, 0, 0, 0, NULL, - SMP_MSG_FLAG_ASYNC); - } - } - } - } - - // notify listeners - NotifySchedulerListeners(&SchedulerListener::ThreadEnqueuedInRunQueue, - thread); -} - - -/*! Sets the priority of a thread. - Note: thread lock must be held when entering this function -*/ -static void -set_thread_priority(Thread *thread, int32 priority) -{ - if (priority == thread->priority) - return; - - if (thread->state != B_THREAD_READY) { - thread->priority = priority; - return; - } - - // The thread is in the run queue. We need to remove it and re-insert it at - // a new position. - - T(RemoveThread(thread)); - - // notify listeners - NotifySchedulerListeners(&SchedulerListener::ThreadRemovedFromRunQueue, - thread); - - // find thread in run queue - Thread *item, *prev; - for (item = sRunQueue, prev = NULL; item && item != thread; - item = item->queue_next) { - if (prev) - prev = prev->queue_next; - else - prev = sRunQueue; - } - - ASSERT(item == thread); - - // remove the thread - if (prev) - prev->queue_next = item->queue_next; - else - sRunQueue = item->queue_next; - - // set priority and re-insert - thread->priority = thread->next_priority = priority; - enqueue_in_run_queue(thread); -} - - -static bigtime_t -estimate_max_scheduling_latency(Thread* thread) -{ - // TODO: This is probably meant to be called periodically to return the - // current estimate depending on the system usage; we return fixed estimates - // per thread priority, though. - - if (thread->priority >= B_REAL_TIME_DISPLAY_PRIORITY) - return kThreadQuantum / 4; - if (thread->priority >= B_DISPLAY_PRIORITY) - return kThreadQuantum; - - return 2 * kThreadQuantum; -} - - -static int32 -reschedule_event(timer *unused) -{ - // This function is called as a result of the timer event set by the - // scheduler. Make sure the reschedule() is invoked. - thread_get_current_thread()->cpu->invoke_scheduler = true; - thread_get_current_thread()->cpu->invoke_scheduler_if_idle = false; - thread_get_current_thread()->cpu->preempted = 1; - return B_HANDLED_INTERRUPT; -} - - -/*! Runs the scheduler. - Note: expects thread spinlock to be held -*/ -static void -reschedule(void) -{ - Thread *oldThread = thread_get_current_thread(); - Thread *nextThread, *prevThread; - - // check whether we're only supposed to reschedule, if the current thread - // is idle - if (oldThread->cpu->invoke_scheduler) { - oldThread->cpu->invoke_scheduler = false; - if (oldThread->cpu->invoke_scheduler_if_idle - && oldThread->priority != B_IDLE_PRIORITY) { - oldThread->cpu->invoke_scheduler_if_idle = false; - return; - } - } - - TRACE(("reschedule(): cpu %ld, cur_thread = %ld\n", smp_get_current_cpu(), - thread_get_current_thread()->id)); - - oldThread->state = oldThread->next_state; - switch (oldThread->next_state) { - case B_THREAD_RUNNING: - case B_THREAD_READY: - TRACE(("enqueueing thread %ld into run q. pri = %ld\n", - oldThread->id, oldThread->priority)); - enqueue_in_run_queue(oldThread); - break; - case B_THREAD_SUSPENDED: - TRACE(("reschedule(): suspending thread %ld\n", oldThread->id)); - break; - case THREAD_STATE_FREE_ON_RESCHED: - break; - default: - TRACE(("not enqueueing thread %ld into run q. next_state = %ld\n", - oldThread->id, oldThread->next_state)); - break; - } - - nextThread = sRunQueue; - prevThread = NULL; - - if (oldThread->cpu->disabled) { - // CPU is disabled - service any threads we may have that are pinned, - // otherwise just select the idle thread - while (nextThread != NULL && nextThread->priority > B_IDLE_PRIORITY) { - if (nextThread->pinned_to_cpu > 0 - && nextThread->previous_cpu == oldThread->cpu) - break; - prevThread = nextThread; - nextThread = nextThread->queue_next; - } - } else { - while (nextThread != NULL) { - // select next thread from the run queue - // TODO: nextThread cannot really be NULL here, so we should be able - // to remove the check, as well as the panic later on. - while (nextThread != NULL - && nextThread->priority > B_IDLE_PRIORITY) { -#if 0 - if (oldThread == nextThread && nextThread->was_yielded) { - // ignore threads that called thread_yield() once - nextThread->was_yielded = false; - prevThread = nextThread; - nextThread = nextThread->queue_next; - } -#endif - - // skip thread, if it doesn't want to run on this CPU - if (nextThread->pinned_to_cpu > 0 - && nextThread->previous_cpu != oldThread->cpu) { - prevThread = nextThread; - nextThread = nextThread->queue_next; - continue; - } - - // always extract real time threads - if (nextThread->priority >= B_FIRST_REAL_TIME_PRIORITY) - break; - - // find next thread with lower priority - Thread *lowerNextThread = nextThread->queue_next; - Thread *lowerPrevThread = nextThread; - int32 priority = nextThread->priority; - - while (lowerNextThread != NULL - && priority == lowerNextThread->priority) { - lowerPrevThread = lowerNextThread; - lowerNextThread = lowerNextThread->queue_next; - } - // never skip last non-idle normal thread - if (lowerNextThread == NULL - || lowerNextThread->priority == B_IDLE_PRIORITY) - break; - - int32 priorityDiff = priority - lowerNextThread->priority; - if (priorityDiff > 15) - break; - - // skip normal threads sometimes - // (twice as probable per priority level) - if ((fast_random_value() >> (15 - priorityDiff)) != 0) - break; - - nextThread = lowerNextThread; - prevThread = lowerPrevThread; - } - - if (nextThread != NULL && nextThread->cpu - && nextThread->cpu->cpu_num != oldThread->cpu->cpu_num) { - panic("thread in run queue that's still running on another CPU!\n"); - // TODO: remove this check completely when we're sure that this - // cannot happen anymore. - prevThread = nextThread; - nextThread = nextThread->queue_next; - continue; - } - - break; - } - } - - if (nextThread == NULL) - panic("reschedule(): run queue is empty!\n"); - - // extract selected thread from the run queue - if (prevThread != NULL) - prevThread->queue_next = nextThread->queue_next; - else - sRunQueue = nextThread->queue_next; - - T(ScheduleThread(nextThread, oldThread)); - - // notify listeners - NotifySchedulerListeners(&SchedulerListener::ThreadScheduled, oldThread, - nextThread); - - nextThread->state = B_THREAD_RUNNING; - nextThread->next_state = B_THREAD_READY; - oldThread->was_yielded = false; - - // track kernel time (user time is tracked in thread_at_kernel_entry()) - scheduler_update_thread_times(oldThread, nextThread); - - // track CPU activity - if (!thread_is_idle_thread(oldThread)) { - oldThread->cpu->active_time - += (oldThread->kernel_time - oldThread->cpu->last_kernel_time) - + (oldThread->user_time - oldThread->cpu->last_user_time); - } - - if (!thread_is_idle_thread(nextThread)) { - oldThread->cpu->last_kernel_time = nextThread->kernel_time; - oldThread->cpu->last_user_time = nextThread->user_time; - } - - if (nextThread != oldThread || oldThread->cpu->preempted) { - bigtime_t quantum = kThreadQuantum; // TODO: calculate quantum? - timer* quantumTimer = &oldThread->cpu->quantum_timer; - - if (!oldThread->cpu->preempted) - cancel_timer(quantumTimer); - - oldThread->cpu->preempted = 0; - if (!thread_is_idle_thread(nextThread)) { - add_timer(quantumTimer, &reschedule_event, quantum, - B_ONE_SHOT_RELATIVE_TIMER | B_TIMER_ACQUIRE_SCHEDULER_LOCK); - } - - if (nextThread != oldThread) - scheduler_switch_thread(oldThread, nextThread); - } -} - - -static status_t -on_thread_create(Thread* thread, bool idleThread) -{ - // do nothing - return B_OK; -} - - -static void -on_thread_init(Thread* thread) -{ - // do nothing -} - - -static void -on_thread_destroy(Thread* thread) -{ - // do nothing -} - - -/*! This starts the scheduler. Must be run in the context of the initial idle - thread. Interrupts must be disabled and will be disabled when returning. -*/ -static void -start(void) -{ - SpinLocker schedulerLocker(gSchedulerLock); - - reschedule(); -} - - -static scheduler_ops kSimpleSMPOps = { - enqueue_in_run_queue, - reschedule, - set_thread_priority, - estimate_max_scheduling_latency, - on_thread_create, - on_thread_init, - on_thread_destroy, - start -}; - - -// #pragma mark - - - -void -scheduler_simple_smp_init() -{ - sCPUCount = smp_get_num_cpus(); - - gScheduler = &kSimpleSMPOps; - - add_debugger_command_etc("run_queue", &dump_run_queue, - "List threads in run queue", "\nLists threads in run queue", 0); -} diff --git a/src/system/kernel/scheduler/scheduler_simple_smp.h b/src/system/kernel/scheduler/scheduler_simple_smp.h deleted file mode 100644 index 67b482494c..0000000000 --- a/src/system/kernel/scheduler/scheduler_simple_smp.h +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright 2008-2009, Ingo Weinhold, ingo_weinhold@gmx.de. - * Distributed under the terms of the MIT License. - */ -#ifndef KERNEL_SCHEDULER_SIMPLE_SMP_H -#define KERNEL_SCHEDULER_SIMPLE_SMP_H - - -void scheduler_simple_smp_init(); - - -#endif // KERNEL_SCHEDULER_SIMPLE_SMP_H diff --git a/src/system/kernel/scheduler/scheduler_thread.cpp b/src/system/kernel/scheduler/scheduler_thread.cpp new file mode 100644 index 0000000000..8651c5cacc --- /dev/null +++ b/src/system/kernel/scheduler/scheduler_thread.cpp @@ -0,0 +1,304 @@ +/* + * Copyright 2013, Paweł Dziepak, pdziepak@quarnos.org. + * Distributed under the terms of the MIT License. + */ + +#include "scheduler_thread.h" + + +using namespace Scheduler; + + +static bigtime_t sQuantumLengths[THREAD_MAX_SET_PRIORITY + 1]; + +const int32 kMaximumQuantumLengthsCount = 20; +static bigtime_t sMaximumQuantumLengths[kMaximumQuantumLengthsCount]; + + +void +ThreadData::_InitBase() +{ + fPriorityPenalty = 0; + fAdditionalPenalty = 0; + fEffectivePriority = GetPriority(); + fBaseQuantum = sQuantumLengths[GetEffectivePriority()]; + fCPUBound = false; + + fTimeUsed = 0; + fStolenTime = 0; + + fMeasureAvailableActiveTime = 0; + fLastMeasureAvailableTime = 0; + fMeasureAvailableTime = 0; + + fNeededLoad = 0; + + fWentSleep = 0; + fWentSleepActive = 0; + fWentSleepCount = 0; + fWentSleepCountIdle = 0; + + fEnqueued = false; + fReady = false; +} + + +inline CoreEntry* +ThreadData::_ChooseCore() const +{ + SCHEDULER_ENTER_FUNCTION(); + + ASSERT(!gSingleCore); + return gCurrentMode->choose_core(this); +} + + +inline CPUEntry* +ThreadData::_ChooseCPU(CoreEntry* core, bool& rescheduleNeeded) const +{ + SCHEDULER_ENTER_FUNCTION(); + + int32 threadPriority = GetEffectivePriority(); + + if (fThread->previous_cpu != NULL) { + CPUEntry* previousCPU + = CPUEntry::GetCPU(fThread->previous_cpu->cpu_num); + if (previousCPU->Core() == core && !fThread->previous_cpu->disabled) { + CoreCPUHeapLocker _(core); + if (CPUPriorityHeap::GetKey(previousCPU) < threadPriority) { + previousCPU->UpdatePriority(threadPriority); + rescheduleNeeded = true; + return previousCPU; + } + } + } + + CoreCPUHeapLocker _(core); + CPUEntry* cpu = core->CPUHeap()->PeekRoot(); + ASSERT(cpu != NULL); + + if (CPUPriorityHeap::GetKey(cpu) < threadPriority) { + cpu->UpdatePriority(threadPriority); + rescheduleNeeded = true; + } else + rescheduleNeeded = false; + + return cpu; +} + + +ThreadData::ThreadData(Thread* thread) + : + fThread(thread) +{ +} + + +void +ThreadData::Init() +{ + _InitBase(); + + Thread* currentThread = thread_get_current_thread(); + ThreadData* currentThreadData = currentThread->scheduler_data; + fCore = currentThreadData->fCore; + + if (!IsRealTime()) { + fPriorityPenalty = std::min(currentThreadData->fPriorityPenalty, + std::max(GetPriority() - _GetMinimalPriority(), int32(0))); + fAdditionalPenalty = currentThreadData->fAdditionalPenalty; + + _ComputeEffectivePriority(); + } +} + + +void +ThreadData::Init(CoreEntry* core) +{ + _InitBase(); + + fCore = core; + fReady = true; +} + + +void +ThreadData::Dump() const +{ + kprintf("\tpriority_penalty:\t%" B_PRId32 "\n", fPriorityPenalty); + + int32 additionalPenalty = 0; + const int kMinimalPriority = _GetMinimalPriority(); + if (kMinimalPriority > 0) + additionalPenalty = fAdditionalPenalty % kMinimalPriority; + kprintf("\tadditional_penalty:\t%" B_PRId32 " (%" B_PRId32 ")\n", + additionalPenalty, fAdditionalPenalty); + kprintf("\teffective_priority:\t%" B_PRId32 "\n", GetEffectivePriority()); + + kprintf("\ttime_used:\t\t%" B_PRId64 " us (quantum: %" B_PRId64 " us)\n", + fTimeUsed, ComputeQuantum()); + kprintf("\tstolen_time:\t\t%" B_PRId64 " us\n", fStolenTime); + kprintf("\tquantum_start:\t\t%" B_PRId64 " us\n", fQuantumStart); + kprintf("\tneeded_load:\t\t%" B_PRId32 "%%\n", fNeededLoad / 10); + kprintf("\twent_sleep:\t\t%" B_PRId64 "\n", fWentSleep); + kprintf("\twent_sleep_active:\t%" B_PRId64 "\n", fWentSleepActive); + kprintf("\twent_sleep_count:\t%" B_PRId32 "\n", fWentSleepCount); + kprintf("\tcore:\t\t\t%" B_PRId32 "\n", + fCore != NULL ? fCore->ID() : -1); + if (fCore != NULL && HasCacheExpired()) + kprintf("\tcache affinity has expired\n"); +} + + +bool +ThreadData::ChooseCoreAndCPU(CoreEntry*& targetCore, CPUEntry*& targetCPU) +{ + SCHEDULER_ENTER_FUNCTION(); + + bool rescheduleNeeded = false; + + if (targetCore == NULL && targetCPU != NULL) + targetCore = targetCPU->Core(); + else if (targetCore != NULL && targetCPU == NULL) + targetCPU = _ChooseCPU(targetCore, rescheduleNeeded); + else if (targetCore == NULL && targetCPU == NULL) { + targetCore = _ChooseCore(); + targetCPU = _ChooseCPU(targetCore, rescheduleNeeded); + } + + ASSERT(targetCore != NULL); + ASSERT(targetCPU != NULL); + + if (fReady && fCore != targetCore && fCore != NULL) { + fCore->UpdateLoad(-fNeededLoad); + targetCore->UpdateLoad(fNeededLoad); + } + + fCore = targetCore; + return rescheduleNeeded; +} + + +bigtime_t +ThreadData::ComputeQuantum() const +{ + SCHEDULER_ENTER_FUNCTION(); + + if (IsRealTime()) + return fBaseQuantum; + + int32 threadCount = fCore->ThreadCount(); + if (fCore->CPUCount() > 0) + threadCount /= fCore->CPUCount(); + + bigtime_t quantum = fBaseQuantum; + if (threadCount < kMaximumQuantumLengthsCount) + quantum = std::min(sMaximumQuantumLengths[threadCount], quantum); + return quantum; +} + + +/* static */ void +ThreadData::ComputeQuantumLengths() +{ + SCHEDULER_ENTER_FUNCTION(); + + for (int32 priority = 0; priority <= THREAD_MAX_SET_PRIORITY; priority++) { + const bigtime_t kQuantum0 = gCurrentMode->base_quantum; + if (priority >= B_URGENT_DISPLAY_PRIORITY) { + sQuantumLengths[priority] = kQuantum0; + continue; + } + + const bigtime_t kQuantum1 + = kQuantum0 * gCurrentMode->quantum_multipliers[0]; + if (priority > B_NORMAL_PRIORITY) { + sQuantumLengths[priority] = _ScaleQuantum(kQuantum1, kQuantum0, + B_URGENT_DISPLAY_PRIORITY, B_NORMAL_PRIORITY, priority); + continue; + } + + const bigtime_t kQuantum2 + = kQuantum0 * gCurrentMode->quantum_multipliers[1]; + sQuantumLengths[priority] = _ScaleQuantum(kQuantum2, kQuantum1, + B_NORMAL_PRIORITY, B_IDLE_PRIORITY, priority); + } + + for (int32 threadCount = 0; threadCount < kMaximumQuantumLengthsCount; + threadCount++) { + + bigtime_t quantum = gCurrentMode->maximum_latency; + if (threadCount != 0) + quantum /= threadCount; + quantum = std::max(quantum, gCurrentMode->minimal_quantum); + sMaximumQuantumLengths[threadCount] = quantum; + } +} + + +inline int32 +ThreadData::_GetPenalty() const +{ + SCHEDULER_ENTER_FUNCTION(); + return fPriorityPenalty; +} + + +void +ThreadData::_ComputeNeededLoad() +{ + SCHEDULER_ENTER_FUNCTION(); + + int32 oldLoad = compute_load(fLastMeasureAvailableTime, + fMeasureAvailableActiveTime, fNeededLoad, fMeasureAvailableTime); + if (oldLoad < 0 || oldLoad == fNeededLoad) + return; + + int32 delta = fNeededLoad - oldLoad; + fCore->UpdateLoad(delta); +} + + +void +ThreadData::_ComputeEffectivePriority() const +{ + SCHEDULER_ENTER_FUNCTION(); + + if (IsIdle()) + fEffectivePriority = B_IDLE_PRIORITY; + else if (IsRealTime()) + fEffectivePriority = GetPriority(); + else { + fEffectivePriority = GetPriority(); + fEffectivePriority -= _GetPenalty(); + if (fEffectivePriority > 0) + fEffectivePriority -= fAdditionalPenalty % fEffectivePriority; + + ASSERT(fEffectivePriority < B_FIRST_REAL_TIME_PRIORITY); + ASSERT(fEffectivePriority >= B_LOWEST_ACTIVE_PRIORITY); + } + + fBaseQuantum = sQuantumLengths[GetEffectivePriority()]; +} + + +/* static */ bigtime_t +ThreadData::_ScaleQuantum(bigtime_t maxQuantum, bigtime_t minQuantum, + int32 maxPriority, int32 minPriority, int32 priority) +{ + SCHEDULER_ENTER_FUNCTION(); + + ASSERT(priority <= maxPriority); + ASSERT(priority >= minPriority); + + bigtime_t result = (maxQuantum - minQuantum) * (priority - minPriority); + result /= maxPriority - minPriority; + return maxQuantum - result; +} + + +ThreadProcessing::~ThreadProcessing() +{ +} + diff --git a/src/system/kernel/scheduler/scheduler_thread.h b/src/system/kernel/scheduler/scheduler_thread.h new file mode 100644 index 0000000000..980d6c2fff --- /dev/null +++ b/src/system/kernel/scheduler/scheduler_thread.h @@ -0,0 +1,493 @@ +/* + * Copyright 2013, Paweł Dziepak, pdziepak@quarnos.org. + * Distributed under the terms of the MIT License. + */ +#ifndef KERNEL_SCHEDULER_THREAD_H +#define KERNEL_SCHEDULER_THREAD_H + + +#include +#include + +#include "scheduler_common.h" +#include "scheduler_cpu.h" +#include "scheduler_locking.h" +#include "scheduler_profiler.h" + + +namespace Scheduler { + + +struct ThreadData : public DoublyLinkedListLinkImpl, + RunQueueLinkImpl { +private: + inline void _InitBase(); + + inline int32 _GetMinimalPriority() const; + + inline CoreEntry* _ChooseCore() const; + inline CPUEntry* _ChooseCPU(CoreEntry* core, + bool& rescheduleNeeded) const; + +public: + ThreadData(Thread* thread); + + void Init(); + void Init(CoreEntry* core); + + void Dump() const; + + inline int32 GetPriority() const { return fThread->priority; } + inline Thread* GetThread() const { return fThread; } + + inline bool IsRealTime() const; + inline bool IsIdle() const; + + inline bool HasCacheExpired() const; + inline bool ShouldRebalance() const; + + inline int32 GetEffectivePriority() const; + + inline bool IsCPUBound() const { return fCPUBound; } + + inline void CancelPenalty(); + inline bool ShouldCancelPenalty() const; + + bool ChooseCoreAndCPU(CoreEntry*& targetCore, + CPUEntry*& targetCPU); + + inline void SetLastInterruptTime(bigtime_t interruptTime) + { fLastInterruptTime = interruptTime; } + inline void SetStolenInterruptTime(bigtime_t interruptTime); + + bigtime_t ComputeQuantum() const; + inline bigtime_t GetQuantumLeft(); + inline void StartQuantum(); + inline bool HasQuantumEnded(bool wasPreempted, bool hasYielded); + + inline void Continues(); + inline void GoesAway(); + inline void Dies(); + + inline bigtime_t WentSleep() const { return fWentSleep; } + inline bigtime_t WentSleepActive() const { return fWentSleepActive; } + + inline void PutBack(); + inline void Enqueue(); + inline bool Dequeue(); + + inline void UpdateActivity(bigtime_t active); + + inline bool IsEnqueued() const { return fEnqueued; } + inline void SetDequeued() { fEnqueued = false; } + + inline int32 GetLoad() const { return fNeededLoad; } + + inline CoreEntry* Core() const { return fCore; } + inline void UnassignCore(bool running = false); + + static void ComputeQuantumLengths(); + +private: + inline void _IncreasePenalty(); + inline int32 _GetPenalty() const; + + void _ComputeNeededLoad(); + + void _ComputeEffectivePriority() const; + + static bigtime_t _ScaleQuantum(bigtime_t maxQuantum, + bigtime_t minQuantum, int32 maxPriority, + int32 minPriority, int32 priority); + + bigtime_t fStolenTime; + bigtime_t fQuantumStart; + bigtime_t fLastInterruptTime; + + bigtime_t fWentSleep; + bigtime_t fWentSleepActive; + int32 fWentSleepCount; + int32 fWentSleepCountIdle; + + bool fEnqueued; + bool fReady; + + Thread* fThread; + + bool fCPUBound; + int32 fPriorityPenalty; + int32 fAdditionalPenalty; + + mutable int32 fEffectivePriority; + mutable bigtime_t fBaseQuantum; + + bigtime_t fTimeUsed; + + bigtime_t fMeasureAvailableActiveTime; + bigtime_t fMeasureAvailableTime; + bigtime_t fLastMeasureAvailableTime; + + int32 fNeededLoad; + + CoreEntry* fCore; +}; + +class ThreadProcessing { +public: + virtual ~ThreadProcessing(); + + virtual void operator()(ThreadData* thread) = 0; +}; + + +inline int32 +ThreadData::_GetMinimalPriority() const +{ + SCHEDULER_ENTER_FUNCTION(); + + const int32 kDivisor = 5; + + const int32 kMaximalPriority = 25; + const int32 kMinimalPriority = B_LOWEST_ACTIVE_PRIORITY; + + int32 priority = GetPriority() / kDivisor; + return std::max(std::min(priority, kMaximalPriority), kMinimalPriority); +} + + +inline bool +ThreadData::IsRealTime() const +{ + return GetPriority() >= B_FIRST_REAL_TIME_PRIORITY; +} + + +inline bool +ThreadData::IsIdle() const +{ + return GetPriority() == B_IDLE_PRIORITY; +} + + +inline bool +ThreadData::HasCacheExpired() const +{ + SCHEDULER_ENTER_FUNCTION(); + return gCurrentMode->has_cache_expired(this); +} + + +inline bool +ThreadData::ShouldRebalance() const +{ + SCHEDULER_ENTER_FUNCTION(); + + ASSERT(!gSingleCore); + return gCurrentMode->should_rebalance(this); +} + + +inline int32 +ThreadData::GetEffectivePriority() const +{ + SCHEDULER_ENTER_FUNCTION(); + return fEffectivePriority; +} + + +inline void +ThreadData::_IncreasePenalty() +{ + SCHEDULER_ENTER_FUNCTION(); + + if (IsIdle() || IsRealTime()) + return; + + TRACE("increasing thread %ld penalty\n", fThread->id); + + int32 oldPenalty = fPriorityPenalty++; + const int kMinimalPriority = _GetMinimalPriority(); + if (GetPriority() - oldPenalty <= kMinimalPriority) { + fPriorityPenalty = oldPenalty; + fCPUBound = true; + } + + _ComputeEffectivePriority(); +} + + +inline void +ThreadData::CancelPenalty() +{ + SCHEDULER_ENTER_FUNCTION(); + + int32 oldPenalty = fPriorityPenalty; + fPriorityPenalty = 0; + fCPUBound = false; + + if (oldPenalty != 0) { + TRACE("cancelling thread %ld penalty\n", fThread->id); + _ComputeEffectivePriority(); + } +} + + +inline bool +ThreadData::ShouldCancelPenalty() const +{ + SCHEDULER_ENTER_FUNCTION(); + + if (fCore == NULL) + return false; + + if (GetEffectivePriority() != B_LOWEST_ACTIVE_PRIORITY && !IsCPUBound()) { + if (fCore->StarvationCounter() != fWentSleepCount) + return true; + } + + return fCore->StarvationCounterIdle() != fWentSleepCountIdle; +} + + +inline void +ThreadData::SetStolenInterruptTime(bigtime_t interruptTime) +{ + SCHEDULER_ENTER_FUNCTION(); + + interruptTime -= fLastInterruptTime; + fStolenTime += interruptTime; +} + + +inline bigtime_t +ThreadData::GetQuantumLeft() +{ + SCHEDULER_ENTER_FUNCTION(); + + bigtime_t stolenTime = std::min(fStolenTime, gCurrentMode->minimal_quantum); + ASSERT(stolenTime >= 0); + fStolenTime -= stolenTime; + + bigtime_t quantum = ComputeQuantum() - fTimeUsed; + quantum += stolenTime; + quantum = std::max(quantum, gCurrentMode->minimal_quantum); + + return quantum; +} + + +inline void +ThreadData::StartQuantum() +{ + SCHEDULER_ENTER_FUNCTION(); + fQuantumStart = system_time(); +} + + +inline bool +ThreadData::HasQuantumEnded(bool wasPreempted, bool hasYielded) +{ + SCHEDULER_ENTER_FUNCTION(); + + bigtime_t timeUsed = system_time() - fQuantumStart; + ASSERT(timeUsed >= 0); + fTimeUsed += timeUsed; + + bigtime_t timeLeft = ComputeQuantum() - fTimeUsed; + timeLeft = std::max(bigtime_t(0), timeLeft); + + // too little time left, it's better make the next quantum a bit longer + bigtime_t skipTime = gCurrentMode->minimal_quantum / 2; + if (hasYielded || wasPreempted || timeLeft <= skipTime) { + fStolenTime += timeLeft; + timeLeft = 0; + } + + if (timeLeft == 0) { + fAdditionalPenalty++; + _IncreasePenalty(); + fTimeUsed = 0; + return true; + } + + return false; +} + + +inline void +ThreadData::Continues() +{ + SCHEDULER_ENTER_FUNCTION(); + + ASSERT(fReady); + if (gTrackCoreLoad) + _ComputeNeededLoad(); +} + + +inline void +ThreadData::GoesAway() +{ + SCHEDULER_ENTER_FUNCTION(); + + ASSERT(fReady); + + if (!HasQuantumEnded(false, false)) { + fAdditionalPenalty++; + _ComputeEffectivePriority(); + } + + fLastInterruptTime = 0; + + fWentSleep = system_time(); + fWentSleepActive = fCore->GetActiveTime(); + fWentSleepCount = fCore->StarvationCounter(); + fWentSleepCountIdle = fCore->StarvationCounterIdle(); + + if (gTrackCoreLoad) + fCore->UpdateLoad(-fNeededLoad); + fReady = false; +} + + +inline void +ThreadData::Dies() +{ + SCHEDULER_ENTER_FUNCTION(); + + ASSERT(fReady); + if (gTrackCoreLoad) + fCore->UpdateLoad(-fNeededLoad); + fReady = false; +} + + +inline void +ThreadData::PutBack() +{ + SCHEDULER_ENTER_FUNCTION(); + + int32 priority = GetEffectivePriority(); + + if (fThread->pinned_to_cpu > 0) { + ASSERT(fThread->cpu != NULL); + CPUEntry* cpu = CPUEntry::GetCPU(fThread->cpu->cpu_num); + + CPURunQueueLocker _(cpu); + ASSERT(!fEnqueued); + fEnqueued = true; + + cpu->PushFront(this, priority); + } else { + CoreRunQueueLocker _(fCore); + ASSERT(!fEnqueued); + fEnqueued = true; + + fCore->PushFront(this, priority); + } +} + + +inline void +ThreadData::Enqueue() +{ + SCHEDULER_ENTER_FUNCTION(); + + if (!fReady) { + ASSERT(system_time() - fWentSleep > 0); + if (gTrackCoreLoad) { + fMeasureAvailableTime += system_time() - fWentSleep; + + fCore->UpdateLoad(fNeededLoad); + _ComputeNeededLoad(); + } + fReady = true; + } + + fThread->state = B_THREAD_READY; + + int32 priority = GetEffectivePriority(); + + if (fThread->pinned_to_cpu > 0) { + ASSERT(fThread->previous_cpu != NULL); + CPUEntry* cpu = CPUEntry::GetCPU(fThread->previous_cpu->cpu_num); + + CPURunQueueLocker _(cpu); + ASSERT(!fEnqueued); + fEnqueued = true; + + cpu->PushBack(this, priority); + } else { + CoreRunQueueLocker _(fCore); + ASSERT(!fEnqueued); + fEnqueued = true; + + fCore->PushBack(this, priority); + } +} + + +inline bool +ThreadData::Dequeue() +{ + SCHEDULER_ENTER_FUNCTION(); + + if (fThread->pinned_to_cpu > 0) { + ASSERT(fThread->previous_cpu != NULL); + CPUEntry* cpu = CPUEntry::GetCPU(fThread->previous_cpu->cpu_num); + + CPURunQueueLocker _(cpu); + if (!fEnqueued) + return false; + cpu->Remove(this); + ASSERT(!fEnqueued); + return true; + } + + CoreRunQueueLocker _(fCore); + if (!fEnqueued) + return false; + + fCore->Remove(this); + ASSERT(!fEnqueued); + return true; +} + + +inline void +ThreadData::UpdateActivity(bigtime_t active) +{ + SCHEDULER_ENTER_FUNCTION(); + + if (!gTrackCoreLoad) + return; + + fMeasureAvailableTime += active; + fMeasureAvailableActiveTime += active; +} + + +inline void +ThreadData::UnassignCore(bool running) +{ + SCHEDULER_ENTER_FUNCTION(); + + ASSERT(fCore != NULL); + if (!fReady) + fCore = NULL; + + if (running || fThread->state == B_THREAD_READY) { + if (gTrackCoreLoad) + fCore->UpdateLoad(-fNeededLoad); + fReady = false; + fThread->state = B_THREAD_SUSPENDED; + fCore = NULL; + } +} + + +} // namespace Scheduler + + +#endif // KERNEL_SCHEDULER_THREAD_H + diff --git a/src/system/kernel/scheduler/scheduler_tracing.cpp b/src/system/kernel/scheduler/scheduler_tracing.cpp index 858886fe8a..21eab8a0a8 100644 --- a/src/system/kernel/scheduler/scheduler_tracing.cpp +++ b/src/system/kernel/scheduler/scheduler_tracing.cpp @@ -19,8 +19,8 @@ namespace SchedulerTracing { void EnqueueThread::AddDump(TraceOutput& out) { - out.Print("scheduler enqueue %ld \"%s\", priority %d (previous %ld, " - "next %ld)", fID, fName, fPriority, fPreviousID, fNextID); + out.Print("scheduler enqueue %ld \"%s\", effective priority %d, " + "real priority %d", fID, fName, fEffectivePriority, fPriority); } diff --git a/src/system/kernel/scheduler/scheduler_tracing.h b/src/system/kernel/scheduler/scheduler_tracing.h index 422834d3d8..f537a6b6f3 100644 --- a/src/system/kernel/scheduler/scheduler_tracing.h +++ b/src/system/kernel/scheduler/scheduler_tracing.h @@ -36,17 +36,12 @@ protected: class EnqueueThread : public SchedulerTraceEntry { public: - EnqueueThread(Thread* thread, Thread* previous, Thread* next) + EnqueueThread(Thread* thread, int32 effectivePriority) : SchedulerTraceEntry(thread), - fPreviousID(-1), - fNextID(-1), - fPriority(thread->priority) + fPriority(thread->priority), + fEffectivePriority(effectivePriority) { - if (previous != NULL) - fPreviousID = previous->id; - if (next != NULL) - fNextID = next->id; fName = alloc_tracing_buffer_strcpy(thread->name, B_OS_NAME_LENGTH, false); Initialized(); @@ -57,10 +52,9 @@ public: virtual const char* Name() const; private: - thread_id fPreviousID; - thread_id fNextID; char* fName; - uint8 fPriority; + int32 fPriority; + int32 fEffectivePriority; }; diff --git a/src/system/kernel/sem.cpp b/src/system/kernel/sem.cpp index 0b761c2724..b947f2080e 100644 --- a/src/system/kernel/sem.cpp +++ b/src/system/kernel/sem.cpp @@ -330,12 +330,10 @@ uninit_sem_locked(struct sem_entry& sem, char** _name) sem.u.used.select_infos = NULL; // free any threads waiting for this semaphore - SpinLocker schedulerLocker(gSchedulerLock); while (queued_thread* entry = sem.queue.RemoveHead()) { entry->queued = false; - thread_unblock_locked(entry->thread, B_BAD_SEM_ID); + thread_unblock(entry->thread, B_BAD_SEM_ID); } - schedulerLocker.Unlock(); int32 id = sem.id; sem.id = -1; @@ -395,7 +393,7 @@ delete_sem_internal(sem_id id, bool checkPermission) char* name; uninit_sem_locked(sSems[slot], &name); - SpinLocker schedulerLocker(gSchedulerLock); + SpinLocker schedulerLocker(thread_get_current_thread()->scheduler_lock); scheduler_reschedule_if_necessary_locked(); schedulerLocker.Unlock(); @@ -646,9 +644,8 @@ remove_thread_from_sem(queued_thread *entry, struct sem_entry *sem) // for that time, so the blocking state of threads won't change (due to // interruption or timeout). We need that lock anyway when unblocking a // thread. - SpinLocker schedulerLocker(gSchedulerLock); - while ((entry = sem->queue.Head()) != NULL) { + SpinLocker schedulerLocker(entry->thread->scheduler_lock); if (thread_is_blocked(entry->thread)) { // The thread is still waiting. If its count is satisfied, unblock // it. Otherwise we can't unblock any other thread. @@ -667,8 +664,6 @@ remove_thread_from_sem(queued_thread *entry, struct sem_entry *sem) entry->queued = false; } - schedulerLocker.Unlock(); - // select notification, if the semaphore is now acquirable if (sem->u.used.count > 0) notify_sem_select_events(sem, B_EVENT_ACQUIRE_SEMAPHORE); @@ -825,7 +820,7 @@ switch_sem_etc(sem_id semToBeReleased, sem_id id, int32 count, // do a quick check to see if the thread has any pending signals // this should catch most of the cases where the thread had a signal - SpinLocker schedulerLocker(gSchedulerLock); + SpinLocker schedulerLocker(thread->scheduler_lock); if (thread_is_interrupted(thread, flags)) { schedulerLocker.Unlock(); sSems[slot].u.used.count += count; @@ -834,6 +829,8 @@ switch_sem_etc(sem_id semToBeReleased, sem_id id, int32 count, goto err; } + schedulerLocker.Unlock(); + if ((flags & (B_RELATIVE_TIMEOUT | B_ABSOLUTE_TIMEOUT)) == 0) timeout = B_INFINITE_TIMEOUT; @@ -845,7 +842,6 @@ switch_sem_etc(sem_id semToBeReleased, sem_id id, int32 count, thread_prepare_to_block(thread, flags, THREAD_BLOCK_TYPE_SEMAPHORE, (void*)(addr_t)id); - schedulerLocker.Unlock(); RELEASE_SEM_LOCK(sSems[slot]); // release the other semaphore, if any @@ -854,13 +850,9 @@ switch_sem_etc(sem_id semToBeReleased, sem_id id, int32 count, semToBeReleased = -1; } - schedulerLocker.Lock(); - status_t acquireStatus = timeout == B_INFINITE_TIMEOUT - ? thread_block_locked(thread) - : thread_block_with_timeout_locked(flags, timeout); + ? thread_block() : thread_block_with_timeout(flags, timeout); - schedulerLocker.Unlock(); GRAB_SEM_LOCK(sSems[slot]); // If we're still queued, this means the acquiration failed, and we @@ -974,8 +966,6 @@ release_sem_etc(sem_id id, int32 count, uint32 flags) // Grab the scheduler lock, so thread_is_blocked() is reliable (due to // possible interruptions or timeouts, it wouldn't be otherwise). - SpinLocker schedulerLocker(gSchedulerLock); - while (count > 0) { queued_thread* entry = sSems[slot].queue.Head(); if (entry == NULL) { @@ -986,6 +976,7 @@ release_sem_etc(sem_id id, int32 count, uint32 flags) break; } + SpinLocker schedulerLock(entry->thread->scheduler_lock); if (thread_is_blocked(entry->thread)) { // The thread is still waiting. If its count is satisfied, // unblock it. Otherwise we can't unblock any other thread. @@ -1011,8 +1002,6 @@ release_sem_etc(sem_id id, int32 count, uint32 flags) entry->queued = false; } - schedulerLocker.Unlock(); - if (sSems[slot].u.used.count > 0) notify_sem_select_events(&sSems[slot], B_EVENT_ACQUIRE_SEMAPHORE); @@ -1020,7 +1009,8 @@ release_sem_etc(sem_id id, int32 count, uint32 flags) // been told not to. if ((flags & B_DO_NOT_RESCHEDULE) == 0) { semLocker.Unlock(); - schedulerLocker.Lock(); + + SpinLocker _(thread_get_current_thread()->scheduler_lock); scheduler_reschedule_if_necessary_locked(); } diff --git a/src/system/kernel/signal.cpp b/src/system/kernel/signal.cpp index ac1b94890b..896784d362 100644 --- a/src/system/kernel/signal.cpp +++ b/src/system/kernel/signal.cpp @@ -315,7 +315,6 @@ Signal::SetTo(uint32 number) fErrorCode = 0; fSendingProcess = team->id; fSendingUser = team->effective_uid; - // assuming scheduler lock is being held fStatus = 0; fPollBand = 0; fAddress = NULL; @@ -748,7 +747,7 @@ class SigSuspendDone : public AbstractTraceEntry { /*! Updates the given thread's Thread::flags field according to what signals are pending. - The caller must hold the scheduler lock. + The caller must hold \c team->signal_lock. */ static void update_thread_signals_flag(Thread* thread) @@ -763,7 +762,7 @@ update_thread_signals_flag(Thread* thread) /*! Updates the current thread's Thread::flags field according to what signals are pending. - The caller must hold the scheduler lock. + The caller must hold \c team->signal_lock. */ static void update_current_thread_signals_flag() @@ -774,7 +773,7 @@ update_current_thread_signals_flag() /*! Updates all of the given team's threads' Thread::flags fields according to what signals are pending. - The caller must hold the scheduler lock. + The caller must hold \c signal_lock. */ static void update_team_threads_signal_flag(Team* team) @@ -826,7 +825,7 @@ notify_debugger(Thread* thread, Signal* signal, struct sigaction& handler, After dequeuing the signal the Thread::flags field of the affected threads are updated. The caller gets a reference to the returned signal, if any. - The caller must hold the scheduler lock. + The caller must hold \c team->signal_lock. \param thread The thread. \param nonBlocked The mask of non-blocked signals. \param buffer If the signal is not queued this buffer is returned. In this @@ -918,7 +917,7 @@ handle_signals(Thread* thread) Team* team = thread->team; TeamLocker teamLocker(team); - InterruptsSpinLocker schedulerLocker(gSchedulerLock); + InterruptsSpinLocker locker(thread->team->signal_lock); // If userland requested to defer signals, we check now, if this is // possible. @@ -949,7 +948,7 @@ handle_signals(Thread* thread) initialIteration = false; } else { teamLocker.Lock(); - schedulerLocker.Lock(); + locker.Lock(); signalMask = thread->AllPendingSignals() & nonBlockedMask; } @@ -959,7 +958,7 @@ handle_signals(Thread* thread) if ((signalMask & KILL_SIGNALS) == 0 && (atomic_get(&thread->debug_info.flags) & B_THREAD_DEBUG_STOP) != 0) { - schedulerLocker.Unlock(); + locker.Unlock(); teamLocker.Unlock(); user_debug_stop_thread(); @@ -978,7 +977,7 @@ handle_signals(Thread* thread) ASSERT(signal != NULL); SignalHandledCaller signalHandledCaller(signal); - schedulerLocker.Unlock(); + locker.Unlock(); // get the action for the signal struct sigaction handler; @@ -1066,7 +1065,7 @@ handle_signals(Thread* thread) team->LockTeamAndParent(false); team_set_job_control_state(team, - JOB_CONTROL_STATE_CONTINUED, signal, false); + JOB_CONTROL_STATE_CONTINUED, signal); team->UnlockTeamAndParent(); @@ -1101,7 +1100,7 @@ handle_signals(Thread* thread) team->LockTeamAndParent(false); team_set_job_control_state(team, - JOB_CONTROL_STATE_STOPPED, signal, false); + JOB_CONTROL_STATE_STOPPED, signal); // send a SIGCHLD to the parent (if it does have // SA_NOCLDSTOP defined) @@ -1124,13 +1123,15 @@ handle_signals(Thread* thread) // Suspend the thread, unless there's already a signal to // continue or kill pending. - InterruptsSpinLocker schedulerLocker(gSchedulerLock); - if ((thread->AllPendingSignals() - & (CONTINUE_SIGNALS | KILL_SIGNALS)) == 0) { - thread->next_state = B_THREAD_SUSPENDED; - scheduler_reschedule(); + locker.Lock(); + bool resume = (thread->AllPendingSignals() + & (CONTINUE_SIGNALS | KILL_SIGNALS)) != 0; + locker.Unlock(); + + if (!resume) { + InterruptsSpinLocker _(thread->scheduler_lock); + scheduler_reschedule(B_THREAD_SUSPENDED); } - schedulerLocker.Unlock(); continue; } @@ -1217,7 +1218,7 @@ handle_signals(Thread* thread) TRACE(("### Setting up custom signal handler frame...\n")); // save the old block mask -- we may need to adjust it for the handler - schedulerLocker.Lock(); + locker.Lock(); sigset_t oldBlockMask = thread->sigsuspend_original_unblocked_mask != 0 ? ~thread->sigsuspend_original_unblocked_mask @@ -1234,7 +1235,7 @@ handle_signals(Thread* thread) update_current_thread_signals_flag(); - schedulerLocker.Unlock(); + locker.Unlock(); setup_signal_frame(thread, &handler, signal, oldBlockMask); @@ -1265,7 +1266,7 @@ handle_signals(Thread* thread) /*! Checks whether the given signal is blocked for the given team (i.e. all of its threads). - The caller must hold the team's lock and the scheduler lock. + The caller must hold the team's lock and \c signal_lock. */ bool is_team_signal_blocked(Team* team, int signal) @@ -1310,7 +1311,7 @@ signal_get_user_stack(addr_t address, stack_t* stack) /*! Checks whether any non-blocked signal is pending for the current thread. - The caller must hold the scheduler lock. + The caller must hold \c team->signal_lock. \param thread The current thread. */ static bool @@ -1323,19 +1324,13 @@ has_signals_pending(Thread* thread) /*! Checks whether the current user has permission to send a signal to the given target team. - The caller must hold the scheduler lock or \a team's lock. - \param team The target team. - \param schedulerLocked \c true, if the caller holds the scheduler lock, - \c false otherwise. */ static bool -has_permission_to_signal(Team* team, bool schedulerLocked) +has_permission_to_signal(Signal* signal, Team* team) { // get the current user - uid_t currentUser = schedulerLocked - ? thread_get_current_thread()->team->effective_uid - : geteuid(); + uid_t currentUser = signal->SendingUser(); // root is omnipotent -- in the other cases the current user must match the // target team's @@ -1346,7 +1341,7 @@ has_permission_to_signal(Team* team, bool schedulerLocked) /*! Delivers a signal to the \a thread, but doesn't handle the signal -- it just makes sure the thread gets the signal, i.e. unblocks it if needed. - The caller must hold the scheduler lock. + The caller must hold \c team->signal_lock. \param thread The thread the signal shall be delivered to. \param signalNumber The number of the signal to be delivered. If \c 0, no @@ -1373,7 +1368,7 @@ send_signal_to_thread_locked(Thread* thread, uint32 signalNumber, BReference signalReference(signal, true); if ((flags & B_CHECK_PERMISSION) != 0) { - if (!has_permission_to_signal(thread->team, true)) + if (!has_permission_to_signal(signal, thread->team)) return EPERM; } @@ -1382,6 +1377,7 @@ send_signal_to_thread_locked(Thread* thread, uint32 signalNumber, if (thread->team == team_get_kernel_team()) { // Signals to kernel threads will only wake them up + SpinLocker _(thread->scheduler_lock); if (thread->state == B_THREAD_SUSPENDED) scheduler_enqueue_in_run_queue(thread); return B_OK; @@ -1405,10 +1401,12 @@ send_signal_to_thread_locked(Thread* thread, uint32 signalNumber, mainThread->AddPendingSignal(SIGKILLTHR); // wake up main thread + SpinLocker locker(mainThread->scheduler_lock); if (mainThread->state == B_THREAD_SUSPENDED) scheduler_enqueue_in_run_queue(mainThread); else thread_interrupt(mainThread, true); + locker.Unlock(); update_thread_signals_flag(mainThread); } @@ -1416,24 +1414,31 @@ send_signal_to_thread_locked(Thread* thread, uint32 signalNumber, // supposed to fall through } case SIGKILLTHR: + { // Wake up suspended threads and interrupt waiting ones + SpinLocker locker(thread->scheduler_lock); if (thread->state == B_THREAD_SUSPENDED) scheduler_enqueue_in_run_queue(thread); else thread_interrupt(thread, true); - break; + break; + } case SIGNAL_CONTINUE_THREAD: + { // wake up thread, and interrupt its current syscall + SpinLocker locker(thread->scheduler_lock); if (thread->state == B_THREAD_SUSPENDED) scheduler_enqueue_in_run_queue(thread); atomic_or(&thread->flags, THREAD_FLAGS_DONT_RESTART_SYSCALL); break; - + } case SIGCONT: + { // Wake up thread if it was suspended, otherwise interrupt it, if // the signal isn't blocked. + SpinLocker locker(thread->scheduler_lock); if (thread->state == B_THREAD_SUSPENDED) scheduler_enqueue_in_run_queue(thread); else if ((SIGNAL_TO_MASK(SIGCONT) & ~thread->sig_block_mask) != 0) @@ -1442,7 +1447,7 @@ send_signal_to_thread_locked(Thread* thread, uint32 signalNumber, // remove any pending stop signals thread->RemovePendingSignals(STOP_SIGNALS); break; - + } default: // If the signal is not masked, interrupt the thread, if it is // currently waiting (interruptibly). @@ -1450,6 +1455,7 @@ send_signal_to_thread_locked(Thread* thread, uint32 signalNumber, & (~thread->sig_block_mask | SIGNAL_TO_MASK(SIGCHLD))) != 0) { // Interrupt thread if it was waiting + SpinLocker locker(thread->scheduler_lock); thread_interrupt(thread, false); } break; @@ -1463,8 +1469,6 @@ send_signal_to_thread_locked(Thread* thread, uint32 signalNumber, /*! Sends the given signal to the given thread. - The caller must not hold the scheduler lock. - \param thread The thread the signal shall be sent to. \param signal The signal to be delivered. If the signal's number is \c 0, no actual signal will be delivered. Only delivery checks will be performed. @@ -1490,15 +1494,19 @@ send_signal_to_thread(Thread* thread, const Signal& signal, uint32 flags) if (error != B_OK) return error; - InterruptsSpinLocker schedulerLocker(gSchedulerLock); + InterruptsReadSpinLocker teamLocker(thread->team_lock); + SpinLocker locker(thread->team->signal_lock); error = send_signal_to_thread_locked(thread, signal.Number(), signalToQueue, flags); if (error != B_OK) return error; + locker.Unlock(); + teamLocker.Unlock(); + if ((flags & B_DO_NOT_RESCHEDULE) == 0) - scheduler_reschedule_if_necessary_locked(); + scheduler_reschedule_if_necessary(); return B_OK; } @@ -1506,8 +1514,6 @@ send_signal_to_thread(Thread* thread, const Signal& signal, uint32 flags) /*! Sends the given signal to the thread with the given ID. - The caller must not hold the scheduler lock. - \param threadID The ID of the thread the signal shall be sent to. \param signal The signal to be delivered. If the signal's number is \c 0, no actual signal will be delivered. Only delivery checks will be performed. @@ -1536,7 +1542,7 @@ send_signal_to_thread_id(thread_id threadID, const Signal& signal, uint32 flags) /*! Sends the given signal to the given team. - The caller must hold the scheduler lock. + The caller must hold \c signal_lock. \param team The team the signal shall be sent to. \param signalNumber The number of the signal to be delivered. If \c 0, no @@ -1567,7 +1573,7 @@ send_signal_to_team_locked(Team* team, uint32 signalNumber, Signal* signal, BReference signalReference(signal, true); if ((flags & B_CHECK_PERMISSION) != 0) { - if (!has_permission_to_signal(team, true)) + if (!has_permission_to_signal(signal, team)) return EPERM; } @@ -1599,6 +1605,7 @@ send_signal_to_team_locked(Team* team, uint32 signalNumber, Signal* signal, mainThread->AddPendingSignal(SIGKILLTHR); // wake up main thread + SpinLocker _(mainThread->scheduler_lock); if (mainThread->state == B_THREAD_SUSPENDED) scheduler_enqueue_in_run_queue(mainThread); else @@ -1612,6 +1619,7 @@ send_signal_to_team_locked(Team* team, uint32 signalNumber, Signal* signal, // don't block the signal. for (Thread* thread = team->thread_list; thread != NULL; thread = thread->team_next) { + SpinLocker _(thread->scheduler_lock); if (thread->state == B_THREAD_SUSPENDED) { scheduler_enqueue_in_run_queue(thread); } else if ((SIGNAL_TO_MASK(SIGCONT) & ~thread->sig_block_mask) @@ -1653,17 +1661,16 @@ send_signal_to_team_locked(Team* team, uint32 signalNumber, Signal* signal, thread = thread->team_next) { sigset_t nonBlocked = ~thread->sig_block_mask | SIGNAL_TO_MASK(SIGCHLD); - if ((thread->AllPendingSignals() & nonBlocked) != 0) + if ((thread->AllPendingSignals() & nonBlocked) != 0) { + SpinLocker _(thread->scheduler_lock); thread_interrupt(thread, false); + } } break; } update_team_threads_signal_flag(team); - if ((flags & B_DO_NOT_RESCHEDULE) == 0) - scheduler_reschedule_if_necessary_locked(); - return B_OK; } @@ -1695,10 +1702,17 @@ send_signal_to_team(Team* team, const Signal& signal, uint32 flags) if (error != B_OK) return error; - InterruptsSpinLocker schedulerLocker(gSchedulerLock); + InterruptsSpinLocker locker(team->signal_lock); - return send_signal_to_team_locked(team, signal.Number(), signalToQueue, - flags); + error = send_signal_to_team_locked(team, signal.Number(), signalToQueue, + flags); + + locker.Unlock(); + + if ((flags & B_DO_NOT_RESCHEDULE) == 0) + scheduler_reschedule_if_necessary(); + + return error; } @@ -1884,7 +1898,7 @@ sigprocmask_internal(int how, const sigset_t* set, sigset_t* oldSet) { Thread* thread = thread_get_current_thread(); - InterruptsSpinLocker schedulerLocker(gSchedulerLock); + InterruptsSpinLocker _(thread->team->signal_lock); sigset_t oldMask = thread->sig_block_mask; @@ -1955,7 +1969,7 @@ sigaction_internal(int signal, const struct sigaction* act, if ((act && act->sa_handler == SIG_IGN) || (act && act->sa_handler == SIG_DFL && (SIGNAL_TO_MASK(signal) & DEFAULT_IGNORE_SIGNALS) != 0)) { - InterruptsSpinLocker schedulerLocker(gSchedulerLock); + InterruptsSpinLocker locker(team->signal_lock); team->RemovePendingSignal(signal); @@ -1997,7 +2011,7 @@ sigwait_internal(const sigset_t* set, siginfo_t* info, uint32 flags, Thread* thread = thread_get_current_thread(); - InterruptsSpinLocker schedulerLocker(gSchedulerLock); + InterruptsSpinLocker locker(thread->team->signal_lock); bool timedOut = false; status_t error = B_OK; @@ -2017,7 +2031,7 @@ sigwait_internal(const sigset_t* set, siginfo_t* info, uint32 flags, ASSERT(signal != NULL); SignalHandledCaller signalHandledCaller(signal); - schedulerLocker.Unlock(); + locker.Unlock(); info->si_signo = signal->Number(); info->si_code = signal->SignalCode(); @@ -2049,16 +2063,22 @@ sigwait_internal(const sigset_t* set, siginfo_t* info, uint32 flags, thread_prepare_to_block(thread, flags, THREAD_BLOCK_TYPE_SIGNAL, NULL); + locker.Unlock(); + if ((flags & B_ABSOLUTE_TIMEOUT) != 0) { - error = thread_block_with_timeout_locked(flags, timeout); + error = thread_block_with_timeout(flags, timeout); if (error == B_WOULD_BLOCK || error == B_TIMED_OUT) { error = B_WOULD_BLOCK; // POSIX requires EAGAIN (B_WOULD_BLOCK) on timeout timedOut = true; + + locker.Lock(); break; } } else - thread_block_locked(thread); + thread_block(); + + locker.Lock(); } // restore the original block mask @@ -2084,7 +2104,7 @@ sigsuspend_internal(const sigset_t* _mask) Thread* thread = thread_get_current_thread(); - InterruptsSpinLocker schedulerLocker(gSchedulerLock); + InterruptsSpinLocker locker(thread->team->signal_lock); // Set the new block mask and block until interrupted. We might be here // after a syscall restart, in which case sigsuspend_original_unblocked_mask @@ -2098,7 +2118,10 @@ sigsuspend_internal(const sigset_t* _mask) while (!has_signals_pending(thread)) { thread_prepare_to_block(thread, B_CAN_INTERRUPT, THREAD_BLOCK_TYPE_SIGNAL, NULL); - thread_block_locked(thread); + + locker.Unlock(); + thread_block(); + locker.Lock(); } // Set sigsuspend_original_unblocked_mask (guaranteed to be non-0 due to @@ -2123,7 +2146,7 @@ sigpending_internal(sigset_t* set) if (set == NULL) return B_BAD_VALUE; - InterruptsSpinLocker schedulerLocker(gSchedulerLock); + InterruptsSpinLocker locker(thread->team->signal_lock); *set = thread->AllPendingSignals() & thread->sig_block_mask; @@ -2414,13 +2437,13 @@ _user_restore_signal_frame(struct signal_frame_data* userSignalFrameData) } // restore the signal block mask - InterruptsSpinLocker schedulerLocker(gSchedulerLock); + InterruptsSpinLocker locker(thread->team->signal_lock); thread->sig_block_mask = signalFrameData.context.uc_sigmask & BLOCKABLE_SIGNALS; update_current_thread_signals_flag(); - schedulerLocker.Unlock(); + locker.Unlock(); // restore the syscall restart related thread flags and the syscall restart // parameters diff --git a/src/system/kernel/smp.cpp b/src/system/kernel/smp.cpp index bf5f7c7603..325fa7206d 100644 --- a/src/system/kernel/smp.cpp +++ b/src/system/kernel/smp.cpp @@ -1,4 +1,5 @@ /* + * Copyright 2013, Paweł Dziepak, pdziepak@quarnos.org. * Copyright 2008-2009, Ingo Weinhold, ingo_weinhold@gmx.de. * Copyright 2002-2010, Axel Dörfler, axeld@pinc-software.de. * Distributed under the terms of the MIT License. @@ -16,6 +17,7 @@ #include #include +#include #include #include #include @@ -26,6 +28,7 @@ #include #include #include +#include #if DEBUG_SPINLOCK_LATENCIES # include #endif @@ -35,9 +38,9 @@ //#define TRACE_SMP #ifdef TRACE_SMP -# define TRACE(x) dprintf x +# define TRACE(...) dprintf_no_syslog(__VA_ARGS__) #else -# define TRACE(x) ; +# define TRACE(...) (void)0 #endif @@ -45,6 +48,19 @@ #undef acquire_spinlock #undef release_spinlock +#undef try_acquire_read_spinlock +#undef acquire_read_spinlock +#undef release_read_spinlock +#undef try_acquire_write_spinlock +#undef acquire_write_spinlock +#undef release_write_spinlock + +#undef try_acquire_write_seqlock +#undef acquire_write_seqlock +#undef release_write_seqlock +#undef acquire_read_seqlock +#undef release_read_seqlock + #define MSG_POOL_SIZE (SMP_MAX_CPUS * 4) @@ -64,8 +80,8 @@ struct smp_msg { void *data_ptr; uint32 flags; int32 ref_count; - volatile bool done; - uint32 proc_bitmap; + int32 done; + CPUSet proc_bitmap; }; enum mailbox_source { @@ -73,21 +89,22 @@ enum mailbox_source { MAILBOX_BCAST, }; -static vint32 sBootCPUSpin = 0; +static int32 sBootCPUSpin = 0; -static vint32 sEarlyCPUCall = 0; +static int32 sEarlyCPUCallCount; +static CPUSet sEarlyCPUCallSet; static void (*sEarlyCPUCallFunction)(void*, int); void* sEarlyCPUCallCookie; static struct smp_msg* sFreeMessages = NULL; -static volatile int sFreeMessageCount = 0; +static int32 sFreeMessageCount = 0; static spinlock sFreeMessageSpinlock = B_SPINLOCK_INITIALIZER; static struct smp_msg* sCPUMessages[SMP_MAX_CPUS] = { NULL, }; -static spinlock sCPUMessageSpinlock[SMP_MAX_CPUS]; static struct smp_msg* sBroadcastMessages = NULL; static spinlock sBroadcastMessageSpinlock = B_SPINLOCK_INITIALIZER; +static int32 sBroadcastMessageCounter; static bool sICIEnabled = false; static int32 sNumCPUs = 1; @@ -103,7 +120,7 @@ static struct { spinlock *lock; } sLastCaller[NUM_LAST_CALLERS]; -static vint32 sLastIndex = 0; +static int32 sLastIndex = 0; // Is incremented atomically. Must be % NUM_LAST_CALLERS before being used // as index into sLastCaller. Note, that it has to be casted to uint32 // before applying the modulo operation, since otherwise after overflowing @@ -123,7 +140,7 @@ push_lock_caller(void* caller, spinlock* lock) static void* find_lock_caller(spinlock* lock) { - int32 lastIndex = (uint32)sLastIndex % NUM_LAST_CALLERS; + int32 lastIndex = (uint32)atomic_get(&sLastIndex) % NUM_LAST_CALLERS; for (int32 i = 0; i < NUM_LAST_CALLERS; i++) { int32 index = (NUM_LAST_CALLERS + lastIndex - 1 - i) % NUM_LAST_CALLERS; @@ -172,9 +189,9 @@ dump_spinlock(int argc, char** argv) static struct { spinlock *lock; bigtime_t timestamp; -} sLatency[B_MAX_CPU_COUNT][NUM_LATENCY_LOCKS]; +} sLatency[SMP_MAX_CPUS][NUM_LATENCY_LOCKS]; -static int32 sLatencyIndex[B_MAX_CPU_COUNT]; +static int32 sLatencyIndex[SMP_MAX_CPUS]; static bool sEnableLatencyCheck; @@ -227,7 +244,7 @@ dump_ici_messages(int argc, char** argv) smp_msg* message = sBroadcastMessages; while (message != NULL) { count++; - if (message->done) + if (message->done == 1) doneCount++; if (message->ref_count <= 0) unreferencedCount++; @@ -278,8 +295,14 @@ dump_ici_message(int argc, char** argv) kprintf(" data_ptr: %p\n", message->data_ptr); kprintf(" flags: %" B_PRIx32 "\n", message->flags); kprintf(" ref_count: %" B_PRIx32 "\n", message->ref_count); - kprintf(" done: %s\n", message->done ? "true" : "false"); - kprintf(" proc_bitmap: %" B_PRIx32 "\n", message->proc_bitmap); + kprintf(" done: %s\n", message->done == 1 ? "true" : "false"); + + kprintf(" proc_bitmap: "); + for (int32 i = 0; i < sNumCPUs; i++) { + if (message->proc_bitmap.GetBit(i)) + kprintf("%s%" B_PRId32, i != 0 ? ", " : "", i); + } + kprintf("\n"); return 0; } @@ -307,7 +330,7 @@ try_acquire_spinlock(spinlock* lock) if (atomic_add(&lock->lock, 1) != 0) return false; #else - if (atomic_or((int32*)lock, 1) != 0) + if (atomic_get_and_set((int32*)lock, 1) != 0) return false; # if DEBUG_SPINLOCKS @@ -337,7 +360,7 @@ acquire_spinlock(spinlock* lock) #else while (1) { uint32 count = 0; - while (*lock != 0) { + while (atomic_get(&lock->lock) != 0) { if (++count == SPINLOCK_DEADLOCK_COUNT) { panic("acquire_spinlock(): Failed to acquire spinlock %p " "for a long time!", lock); @@ -345,9 +368,9 @@ acquire_spinlock(spinlock* lock) } process_all_pending_ici(currentCPU); - PAUSE(); + cpu_wait(&lock->lock, 0); } - if (atomic_or((int32*)lock, 1) == 0) + if (atomic_get_and_set(&lock->lock, 1) == 0) break; } @@ -358,7 +381,7 @@ acquire_spinlock(spinlock* lock) } else { #if DEBUG_SPINLOCKS int32 oldValue; - oldValue = atomic_or((int32*)lock, 1); + oldValue = atomic_get_and_set(&lock->lock, 1); if (oldValue != 0) { panic("acquire_spinlock: attempt to acquire lock %p twice on " "non-SMP system (last caller: %p, value %" B_PRId32 ")", lock, @@ -391,23 +414,23 @@ acquire_spinlock_nocheck(spinlock *lock) #else while (1) { uint32 count = 0; - while (*lock != 0) { + while (atomic_get(&lock->lock) != 0) { if (++count == SPINLOCK_DEADLOCK_COUNT_NO_CHECK) { panic("acquire_spinlock(): Failed to acquire spinlock %p " "for a long time!", lock); count = 0; } - PAUSE(); + cpu_wait(&lock->lock, 0); } - if (atomic_or((int32*)lock, 1) == 0) + if (atomic_get_and_set(&lock->lock, 1) == 0) break; } #endif } else { #if DEBUG_SPINLOCKS - if (atomic_or((int32*)lock, 1) != 0) { + if (atomic_get_and_set(&lock->lock, 1) != 0) { panic("acquire_spinlock_nocheck: attempt to acquire lock %p twice " "on non-SMP system\n", lock); } @@ -434,7 +457,7 @@ acquire_spinlock_cpu(int32 currentCPU, spinlock *lock) #else while (1) { uint32 count = 0; - while (*lock != 0) { + while (atomic_get(&lock->lock) != 0) { if (++count == SPINLOCK_DEADLOCK_COUNT) { panic("acquire_spinlock_cpu(): Failed to acquire spinlock " "%p for a long time!", lock); @@ -442,9 +465,9 @@ acquire_spinlock_cpu(int32 currentCPU, spinlock *lock) } process_all_pending_ici(currentCPU); - PAUSE(); + cpu_wait(&lock->lock, 0); } - if (atomic_or((int32*)lock, 1) == 0) + if (atomic_get_and_set(&lock->lock, 1) == 0) break; } @@ -455,7 +478,7 @@ acquire_spinlock_cpu(int32 currentCPU, spinlock *lock) } else { #if DEBUG_SPINLOCKS int32 oldValue; - oldValue = atomic_or((int32*)lock, 1); + oldValue = atomic_get_and_set(&lock->lock, 1); if (oldValue != 0) { panic("acquire_spinlock_cpu(): attempt to acquire lock %p twice on " "non-SMP system (last caller: %p, value %" B_PRId32 ")", lock, @@ -492,9 +515,11 @@ release_spinlock(spinlock *lock) } } } -#else - if (atomic_and((int32*)lock, 0) != 1) +#elif DEBUG_SPINLOCKS + if (atomic_get_and_set(&lock->lock, 0) != 1) panic("release_spinlock: lock %p was already released\n", lock); +#else + atomic_set(&lock->lock, 0); #endif } else { #if DEBUG_SPINLOCKS @@ -502,7 +527,7 @@ release_spinlock(spinlock *lock) panic("release_spinlock: attempt to release lock %p with " "interrupts enabled\n", lock); } - if (atomic_and((int32*)lock, 0) != 1) + if (atomic_get_and_set(&lock->lock, 0) != 1) panic("release_spinlock: lock %p was already released\n", lock); #endif #if DEBUG_SPINLOCK_LATENCIES @@ -512,6 +537,180 @@ release_spinlock(spinlock *lock) } +bool +try_acquire_write_spinlock(rw_spinlock* lock) +{ +#if DEBUG_SPINLOCKS + if (are_interrupts_enabled()) { + panic("try_acquire_write_spinlock: attempt to acquire lock %p with " + "interrupts enabled", lock); + } + + if (sNumCPUs < 2 && lock->lock != 0) { + panic("try_acquire_write_spinlock(): attempt to acquire lock %p twice " + "on non-SMP system", lock); + } +#endif + + return atomic_test_and_set(&lock->lock, 1u << 31, 0) == 0; +} + + +void +acquire_write_spinlock(rw_spinlock* lock) +{ +#if DEBUG_SPINLOCKS + if (are_interrupts_enabled()) { + panic("acquire_write_spinlock: attempt to acquire lock %p with " + "interrupts enabled", lock); + } +#endif + + uint32 count = 0; + int currentCPU = smp_get_current_cpu(); + while (true) { + if (try_acquire_write_spinlock(lock)) + break; + + while (atomic_get(&lock->lock) != 0) { + if (++count == SPINLOCK_DEADLOCK_COUNT) { + panic("acquire_write_spinlock(): Failed to acquire spinlock %p " + "for a long time!", lock); + count = 0; + } + + process_all_pending_ici(currentCPU); + cpu_wait(&lock->lock, 0); + } + } +} + + +void +release_write_spinlock(rw_spinlock* lock) +{ +#if DEBUG_SPINLOCKS + uint32 previous = atomic_get_and_set(&lock->lock, 0); + if ((previous & 1u << 31) == 0) { + panic("release_write_spinlock: lock %p was already released (value: " + "%#" B_PRIx32 ")\n", lock, previous); + } +#else + atomic_set(&lock->lock, 0); +#endif +} + + +bool +try_acquire_read_spinlock(rw_spinlock* lock) +{ +#if DEBUG_SPINLOCKS + if (are_interrupts_enabled()) { + panic("try_acquire_read_spinlock: attempt to acquire lock %p with " + "interrupts enabled", lock); + } + + if (sNumCPUs < 2 && lock->lock != 0) { + panic("try_acquire_read_spinlock(): attempt to acquire lock %p twice " + "on non-SMP system", lock); + } +#endif + + uint32 previous = atomic_add(&lock->lock, 1); + return (previous & (1u << 31)) == 0; +} + + +void +acquire_read_spinlock(rw_spinlock* lock) +{ +#if DEBUG_SPINLOCKS + if (are_interrupts_enabled()) { + panic("acquire_read_spinlock: attempt to acquire lock %p with " + "interrupts enabled", lock); + } +#endif + + uint32 count = 0; + int currentCPU = smp_get_current_cpu(); + while (1) { + if (try_acquire_read_spinlock(lock)) + break; + + while (atomic_get(&lock->lock) != 0) { + if (++count == SPINLOCK_DEADLOCK_COUNT) { + panic("acquire_read_spinlock(): Failed to acquire spinlock %p " + "for a long time!", lock); + count = 0; + } + + process_all_pending_ici(currentCPU); + cpu_wait(&lock->lock, 0); + } + } +} + + +void +release_read_spinlock(rw_spinlock* lock) +{ +#if DEBUG_SPINLOCKS + uint32 previous = atomic_add(&lock->lock, -1); + if ((previous & 1u << 31) != 0) { + panic("release_read_spinlock: lock %p was already released (value:" + " %#" B_PRIx32 ")\n", lock, previous); + } +#else + atomic_add(&lock->lock, -1); +#endif + +} + + +bool +try_acquire_write_seqlock(seqlock* lock) { + bool succeed = try_acquire_spinlock(&lock->lock); + if (succeed) + atomic_add((int32*)&lock->count, 1); + return succeed; +} + + +void +acquire_write_seqlock(seqlock* lock) { + acquire_spinlock(&lock->lock); + atomic_add((int32*)&lock->count, 1); +} + + +void +release_write_seqlock(seqlock* lock) { + atomic_add((int32*)&lock->count, 1); + release_spinlock(&lock->lock); +} + + +uint32 +acquire_read_seqlock(seqlock* lock) { + return atomic_get((int32*)&lock->count); +} + + +bool +release_read_seqlock(seqlock* lock, uint32 count) { + memory_read_barrier(); + + uint32 current = atomic_get((int32*)&lock->count); + + if (count % 2 == 1 || current != count) { + cpu_pause(); + return false; + } + + return true; +} + + /*! Finds a free message and gets it. NOTE: has side effect of disabling interrupts return value is the former interrupt state @@ -521,15 +720,12 @@ find_free_message(struct smp_msg** msg) { cpu_status state; - TRACE(("find_free_message: entry\n")); + TRACE("find_free_message: entry\n"); retry: - while (sFreeMessageCount <= 0) { - state = disable_interrupts(); - process_all_pending_ici(smp_get_current_cpu()); - restore_interrupts(state); - PAUSE(); - } + while (atomic_get(&sFreeMessageCount) <= 0) + cpu_pause(); + state = disable_interrupts(); acquire_spinlock(&sFreeMessageSpinlock); @@ -547,7 +743,7 @@ retry: release_spinlock(&sFreeMessageSpinlock); - TRACE(("find_free_message: returning msg %p\n", *msg)); + TRACE("find_free_message: returning msg %p\n", *msg); return state; } @@ -560,13 +756,13 @@ static void find_free_message_interrupts_disabled(int32 currentCPU, struct smp_msg** _message) { - TRACE(("find_free_message_interrupts_disabled: entry\n")); + TRACE("find_free_message_interrupts_disabled: entry\n"); acquire_spinlock_cpu(currentCPU, &sFreeMessageSpinlock); - while (sFreeMessageCount <= 0) { + while (atomic_get(&sFreeMessageCount) <= 0) { release_spinlock(&sFreeMessageSpinlock); process_all_pending_ici(currentCPU); - PAUSE(); + cpu_pause(); acquire_spinlock_cpu(currentCPU, &sFreeMessageSpinlock); } @@ -576,15 +772,15 @@ find_free_message_interrupts_disabled(int32 currentCPU, release_spinlock(&sFreeMessageSpinlock); - TRACE(("find_free_message_interrupts_disabled: returning msg %p\n", - *_message)); + TRACE("find_free_message_interrupts_disabled: returning msg %p\n", + *_message); } static void return_free_message(struct smp_msg* msg) { - TRACE(("return_free_message: returning msg %p\n", msg)); + TRACE("return_free_message: returning msg %p\n", msg); acquire_spinlock_nocheck(&sFreeMessageSpinlock); msg->next = sFreeMessages; @@ -600,37 +796,44 @@ check_for_message(int currentCPU, mailbox_source& sourceMailbox) if (!sICIEnabled) return NULL; - acquire_spinlock_nocheck(&sCPUMessageSpinlock[currentCPU]); - - struct smp_msg* msg = sCPUMessages[currentCPU]; + struct smp_msg* msg = atomic_pointer_get(&sCPUMessages[currentCPU]); if (msg != NULL) { - sCPUMessages[currentCPU] = msg->next; - release_spinlock(&sCPUMessageSpinlock[currentCPU]); - TRACE((" cpu %d: found msg %p in cpu mailbox\n", currentCPU, msg)); - sourceMailbox = MAILBOX_LOCAL; - } else { - // try getting one from the broadcast mailbox + do { + cpu_pause(); + msg = atomic_pointer_get(&sCPUMessages[currentCPU]); + ASSERT(msg != NULL); + } while (atomic_pointer_test_and_set(&sCPUMessages[currentCPU], + msg->next, msg) != msg); - release_spinlock(&sCPUMessageSpinlock[currentCPU]); + TRACE(" cpu %d: found msg %p in cpu mailbox\n", currentCPU, msg); + sourceMailbox = MAILBOX_LOCAL; + } else if (atomic_get(&get_cpu_struct()->ici_counter) + != atomic_get(&sBroadcastMessageCounter)) { + + // try getting one from the broadcast mailbox acquire_spinlock_nocheck(&sBroadcastMessageSpinlock); msg = sBroadcastMessages; while (msg != NULL) { - if (CHECK_BIT(msg->proc_bitmap, currentCPU) != 0) { + if (!msg->proc_bitmap.GetBit(currentCPU)) { // we have handled this one already msg = msg->next; continue; } // mark it so we wont try to process this one again - msg->proc_bitmap = SET_BIT(msg->proc_bitmap, currentCPU); + msg->proc_bitmap.ClearBit(currentCPU); + atomic_add(&gCPU[currentCPU].ici_counter, 1); + sourceMailbox = MAILBOX_BCAST; break; } release_spinlock(&sBroadcastMessageSpinlock); - TRACE((" cpu %d: found msg %p in broadcast mailbox\n", currentCPU, - msg)); + if (msg != NULL) { + TRACE(" cpu %d: found msg %p in broadcast mailbox\n", currentCPU, + msg); + } } return msg; } @@ -645,27 +848,18 @@ finish_message_processing(int currentCPU, struct smp_msg* msg, // we were the last one to decrement the ref_count // it's our job to remove it from the list & possibly clean it up - struct smp_msg** mbox; - spinlock* spinlock; - // clean up the message from one of the mailboxes - if (sourceMailbox == MAILBOX_BCAST) { - mbox = &sBroadcastMessages; - spinlock = &sBroadcastMessageSpinlock; - } else { - mbox = &sCPUMessages[currentCPU]; - spinlock = &sCPUMessageSpinlock[currentCPU]; - } + // clean up the message + if (sourceMailbox == MAILBOX_BCAST) + acquire_spinlock_nocheck(&sBroadcastMessageSpinlock); - acquire_spinlock_nocheck(spinlock); - - TRACE(("cleaning up message %p\n", msg)); + TRACE("cleaning up message %p\n", msg); if (sourceMailbox != MAILBOX_BCAST) { // local mailbox -- the message has already been removed in // check_for_message() - } else if (msg == *mbox) { - *mbox = msg->next; + } else if (msg == sBroadcastMessages) { + sBroadcastMessages = msg->next; } else { // we need to walk to find the message in the list. // we can't use any data found when previously walking through @@ -674,7 +868,7 @@ finish_message_processing(int currentCPU, struct smp_msg* msg, struct smp_msg* last = NULL; struct smp_msg* msg1; - msg1 = *mbox; + msg1 = sBroadcastMessages; while (msg1 != NULL && msg1 != msg) { last = msg1; msg1 = msg1->next; @@ -687,13 +881,14 @@ finish_message_processing(int currentCPU, struct smp_msg* msg, panic("last == NULL or msg != msg1"); } - release_spinlock(spinlock); + if (sourceMailbox == MAILBOX_BCAST) + release_spinlock(&sBroadcastMessageSpinlock); if ((msg->flags & SMP_MSG_FLAG_FREE_ARG) != 0 && msg->data_ptr != NULL) free(msg->data_ptr); if ((msg->flags & SMP_MSG_FLAG_SYNC) != 0) { - msg->done = true; + atomic_set(&msg->done, 1); // the caller cpu should now free the message } else { // in the !SYNC case, we get to free the message @@ -710,7 +905,7 @@ process_pending_ici(int32 currentCPU) if (msg == NULL) return B_ENTRY_NOT_FOUND; - TRACE((" cpu %ld message = %ld\n", currentCPU, msg->message)); + TRACE(" cpu %ld message = %ld\n", currentCPU, msg->message); bool haltCPU = false; @@ -737,21 +932,8 @@ process_pending_ici(int32 currentCPU) break; } case SMP_MSG_RESCHEDULE: - { - cpu_ent* cpu = thread_get_current_thread()->cpu; - cpu->invoke_scheduler = true; - cpu->invoke_scheduler_if_idle = false; + scheduler_reschedule_ici(); break; - } - case SMP_MSG_RESCHEDULE_IF_IDLE: - { - cpu_ent* cpu = thread_get_current_thread()->cpu; - if (!cpu->invoke_scheduler) { - cpu->invoke_scheduler = true; - cpu->invoke_scheduler_if_idle = true; - } - break; - } default: dprintf("smp_intercpu_int_handler: got unknown message %" B_PRId32 "\n", @@ -818,7 +1000,8 @@ static void process_early_cpu_call(int32 cpu) { sEarlyCPUCallFunction(sEarlyCPUCallCookie, cpu); - atomic_and(&sEarlyCPUCall, ~(uint32)(1 << cpu)); + sEarlyCPUCallSet.ClearBit(cpu); + atomic_add(&sEarlyCPUCallCount, 1); } @@ -829,14 +1012,13 @@ call_all_cpus_early(void (*function)(void*, int), void* cookie) sEarlyCPUCallFunction = function; sEarlyCPUCallCookie = cookie; - uint32 cpuMask = (1 << sNumCPUs) - 2; - // all CPUs but the boot cpu - - sEarlyCPUCall = cpuMask; + atomic_set(&sEarlyCPUCallCount, 1); + sEarlyCPUCallSet.SetAll(); + sEarlyCPUCallSet.ClearBit(0); // wait for all CPUs to finish - while ((sEarlyCPUCall & cpuMask) != 0) - PAUSE(); + while (atomic_get(&sEarlyCPUCallCount) < sNumCPUs) + cpu_wait(&sEarlyCPUCallCount, sNumCPUs); } function(cookie, 0); @@ -849,11 +1031,11 @@ call_all_cpus_early(void (*function)(void*, int), void* cookie) int smp_intercpu_int_handler(int32 cpu) { - TRACE(("smp_intercpu_int_handler: entry on cpu %ld\n", cpu)); + TRACE("smp_intercpu_int_handler: entry on cpu %ld\n", cpu); process_all_pending_ici(cpu); - TRACE(("smp_intercpu_int_handler: done\n")); + TRACE("smp_intercpu_int_handler: done on cpu %ld\n", cpu); return B_HANDLED_INTERRUPT; } @@ -865,9 +1047,9 @@ smp_send_ici(int32 targetCPU, int32 message, addr_t data, addr_t data2, { struct smp_msg *msg; - TRACE(("smp_send_ici: target 0x%lx, mess 0x%lx, data 0x%lx, data2 0x%lx, " + TRACE("smp_send_ici: target 0x%lx, mess 0x%lx, data 0x%lx, data2 0x%lx, " "data3 0x%lx, ptr %p, flags 0x%lx\n", targetCPU, message, data, data2, - data3, dataPointer, flags)); + data3, dataPointer, flags); if (sICIEnabled) { int state; @@ -891,13 +1073,16 @@ smp_send_ici(int32 targetCPU, int32 message, addr_t data, addr_t data2, msg->data_ptr = dataPointer; msg->ref_count = 1; msg->flags = flags; - msg->done = false; + msg->done = 0; // stick it in the appropriate cpu's mailbox - acquire_spinlock_nocheck(&sCPUMessageSpinlock[targetCPU]); - msg->next = sCPUMessages[targetCPU]; - sCPUMessages[targetCPU] = msg; - release_spinlock(&sCPUMessageSpinlock[targetCPU]); + struct smp_msg* next; + do { + cpu_pause(); + next = atomic_pointer_get(&sCPUMessages[targetCPU]); + msg->next = next; + } while (atomic_pointer_test_and_set(&sCPUMessages[targetCPU], msg, + next) != next); arch_smp_send_ici(targetCPU); @@ -905,9 +1090,9 @@ smp_send_ici(int32 targetCPU, int32 message, addr_t data, addr_t data2, // wait for the other cpu to finish processing it // the interrupt handler will ref count it to <0 // if the message is sync after it has removed it from the mailbox - while (msg->done == false) { + while (atomic_get(&msg->done) == 0) { process_all_pending_ici(currentCPU); - PAUSE(); + cpu_wait(&msg->done, 1); } // for SYNC messages, it's our responsibility to put it // back into the free list @@ -920,25 +1105,22 @@ smp_send_ici(int32 targetCPU, int32 message, addr_t data, addr_t data2, void -smp_send_multicast_ici(cpu_mask_t cpuMask, int32 message, addr_t data, +smp_send_multicast_ici(CPUSet& cpuMask, int32 message, addr_t data, addr_t data2, addr_t data3, void *dataPointer, uint32 flags) { if (!sICIEnabled) return; int currentCPU = smp_get_current_cpu(); - cpuMask &= ~((cpu_mask_t)1 << currentCPU) - & (((cpu_mask_t)1 << sNumCPUs) - 1); - if (cpuMask == 0) { - panic("smp_send_multicast_ici(): 0 CPU mask"); - return; - } + bool broadcast = true; // count target CPUs int32 targetCPUs = 0; for (int32 i = 0; i < sNumCPUs; i++) { - if ((cpuMask & (cpu_mask_t)1 << i) != 0) + if (cpuMask.GetBit(i)) targetCPUs++; + else if (i != currentCPU) + broadcast = false; } // find_free_message leaves interrupts disabled @@ -952,8 +1134,15 @@ smp_send_multicast_ici(cpu_mask_t cpuMask, int32 message, addr_t data, msg->data_ptr = dataPointer; msg->ref_count = targetCPUs; msg->flags = flags; - msg->proc_bitmap = ~cpuMask; - msg->done = false; + msg->done = 0; + + msg->proc_bitmap = cpuMask; + msg->proc_bitmap.ClearBit(currentCPU); + if (msg->proc_bitmap.IsEmpty()) { + panic("smp_send_multicast_ici(): 0 CPU mask"); + return; + } + // stick it in the broadcast mailbox acquire_spinlock_nocheck(&sBroadcastMessageSpinlock); @@ -961,16 +1150,24 @@ smp_send_multicast_ici(cpu_mask_t cpuMask, int32 message, addr_t data, sBroadcastMessages = msg; release_spinlock(&sBroadcastMessageSpinlock); - arch_smp_send_broadcast_ici(); - // TODO: Introduce a call that only bothers the target CPUs! + atomic_add(&sBroadcastMessageCounter, 1); + for (int32 i = 0; i < sNumCPUs; i++) { + if (!cpuMask.GetBit(i)) + atomic_add(&gCPU[i].ici_counter, 1); + } + + if (broadcast) + arch_smp_send_broadcast_ici(); + else + arch_smp_send_multicast_ici(cpuMask); if ((flags & SMP_MSG_FLAG_SYNC) != 0) { // wait for the other cpus to finish processing it // the interrupt handler will ref count it to <0 // if the message is sync after it has removed it from the mailbox - while (msg->done == false) { + while (atomic_get(&msg->done) == 0) { process_all_pending_ici(currentCPU); - PAUSE(); + cpu_wait(&msg->done, 1); } // for SYNC messages, it's our responsibility to put it @@ -988,9 +1185,9 @@ smp_send_broadcast_ici(int32 message, addr_t data, addr_t data2, addr_t data3, { struct smp_msg *msg; - TRACE(("smp_send_broadcast_ici: cpu %ld mess 0x%lx, data 0x%lx, data2 " + TRACE("smp_send_broadcast_ici: cpu %ld mess 0x%lx, data 0x%lx, data2 " "0x%lx, data3 0x%lx, ptr %p, flags 0x%lx\n", smp_get_current_cpu(), - message, data, data2, data3, dataPointer, flags)); + message, data, data2, data3, dataPointer, flags); if (sICIEnabled) { int state; @@ -1008,11 +1205,12 @@ smp_send_broadcast_ici(int32 message, addr_t data, addr_t data2, addr_t data3, msg->data_ptr = dataPointer; msg->ref_count = sNumCPUs - 1; msg->flags = flags; - msg->proc_bitmap = SET_BIT(0, currentCPU); - msg->done = false; + msg->proc_bitmap.SetAll(); + msg->proc_bitmap.ClearBit(currentCPU); + msg->done = 0; - TRACE(("smp_send_broadcast_ici%d: inserting msg %p into broadcast " - "mbox\n", currentCPU, msg)); + TRACE("smp_send_broadcast_ici%d: inserting msg %p into broadcast " + "mbox\n", currentCPU, msg); // stick it in the appropriate cpu's mailbox acquire_spinlock_nocheck(&sBroadcastMessageSpinlock); @@ -1020,22 +1218,25 @@ smp_send_broadcast_ici(int32 message, addr_t data, addr_t data2, addr_t data3, sBroadcastMessages = msg; release_spinlock(&sBroadcastMessageSpinlock); + atomic_add(&sBroadcastMessageCounter, 1); + atomic_add(&gCPU[currentCPU].ici_counter, 1); + arch_smp_send_broadcast_ici(); - TRACE(("smp_send_broadcast_ici: sent interrupt\n")); + TRACE("smp_send_broadcast_ici: sent interrupt\n"); if ((flags & SMP_MSG_FLAG_SYNC) != 0) { // wait for the other cpus to finish processing it // the interrupt handler will ref count it to <0 // if the message is sync after it has removed it from the mailbox - TRACE(("smp_send_broadcast_ici: waiting for ack\n")); + TRACE("smp_send_broadcast_ici: waiting for ack\n"); - while (msg->done == false) { + while (atomic_get(&msg->done) == 0) { process_all_pending_ici(currentCPU); - PAUSE(); + cpu_wait(&msg->done, 1); } - TRACE(("smp_send_broadcast_ici: returning message to free list\n")); + TRACE("smp_send_broadcast_ici: returning message to free list\n"); // for SYNC messages, it's our responsibility to put it // back into the free list @@ -1045,7 +1246,7 @@ smp_send_broadcast_ici(int32 message, addr_t data, addr_t data2, addr_t data3, restore_interrupts(state); } - TRACE(("smp_send_broadcast_ici: done\n")); + TRACE("smp_send_broadcast_ici: done\n"); } @@ -1056,9 +1257,9 @@ smp_send_broadcast_ici_interrupts_disabled(int32 currentCPU, int32 message, if (!sICIEnabled) return; - TRACE(("smp_send_broadcast_ici_interrupts_disabled: cpu %ld mess 0x%lx, " + TRACE("smp_send_broadcast_ici_interrupts_disabled: cpu %ld mess 0x%lx, " "data 0x%lx, data2 0x%lx, data3 0x%lx, ptr %p, flags 0x%lx\n", - currentCPU, message, data, data2, data3, dataPointer, flags)); + currentCPU, message, data, data2, data3, dataPointer, flags); struct smp_msg *msg; find_free_message_interrupts_disabled(currentCPU, &msg); @@ -1070,11 +1271,12 @@ smp_send_broadcast_ici_interrupts_disabled(int32 currentCPU, int32 message, msg->data_ptr = dataPointer; msg->ref_count = sNumCPUs - 1; msg->flags = flags; - msg->proc_bitmap = SET_BIT(0, currentCPU); - msg->done = false; + msg->proc_bitmap.SetAll(); + msg->proc_bitmap.ClearBit(currentCPU); + msg->done = 0; - TRACE(("smp_send_broadcast_ici_interrupts_disabled %ld: inserting msg %p " - "into broadcast mbox\n", currentCPU, msg)); + TRACE("smp_send_broadcast_ici_interrupts_disabled %ld: inserting msg %p " + "into broadcast mbox\n", currentCPU, msg); // stick it in the appropriate cpu's mailbox acquire_spinlock_nocheck(&sBroadcastMessageSpinlock); @@ -1082,32 +1284,35 @@ smp_send_broadcast_ici_interrupts_disabled(int32 currentCPU, int32 message, sBroadcastMessages = msg; release_spinlock(&sBroadcastMessageSpinlock); + atomic_add(&sBroadcastMessageCounter, 1); + atomic_add(&gCPU[currentCPU].ici_counter, 1); + arch_smp_send_broadcast_ici(); - TRACE(("smp_send_broadcast_ici_interrupts_disabled %ld: sent interrupt\n", - currentCPU)); + TRACE("smp_send_broadcast_ici_interrupts_disabled %ld: sent interrupt\n", + currentCPU); if ((flags & SMP_MSG_FLAG_SYNC) != 0) { // wait for the other cpus to finish processing it // the interrupt handler will ref count it to <0 // if the message is sync after it has removed it from the mailbox - TRACE(("smp_send_broadcast_ici_interrupts_disabled %ld: waiting for " - "ack\n", currentCPU)); + TRACE("smp_send_broadcast_ici_interrupts_disabled %ld: waiting for " + "ack\n", currentCPU); - while (msg->done == false) { + while (atomic_get(&msg->done) == 0) { process_all_pending_ici(currentCPU); - PAUSE(); + cpu_wait(&msg->done, 1); } - TRACE(("smp_send_broadcast_ici_interrupts_disabled %ld: returning " - "message to free list\n", currentCPU)); + TRACE("smp_send_broadcast_ici_interrupts_disabled %ld: returning " + "message to free list\n", currentCPU); // for SYNC messages, it's our responsibility to put it // back into the free list return_free_message(msg); } - TRACE(("smp_send_broadcast_ici_interrupts_disabled: done\n")); + TRACE("smp_send_broadcast_ici_interrupts_disabled: done\n"); } @@ -1122,17 +1327,17 @@ bool smp_trap_non_boot_cpus(int32 cpu, uint32* rendezVous) { if (cpu == 0) { - smp_cpu_rendezvous(rendezVous, cpu); + smp_cpu_rendezvous(rendezVous); return true; } - smp_cpu_rendezvous(rendezVous, cpu); + smp_cpu_rendezvous(rendezVous); - while (sBootCPUSpin == 0) { - if ((sEarlyCPUCall & (1 << cpu)) != 0) + while (atomic_get(&sBootCPUSpin) == 0) { + if (sEarlyCPUCallSet.GetBit(cpu)) process_early_cpu_call(cpu); - PAUSE(); + cpu_pause(); } return false; @@ -1147,7 +1352,7 @@ smp_wake_up_non_boot_cpus() sICIEnabled = true; // resume non boot CPUs - sBootCPUSpin = 1; + atomic_set(&sBootCPUSpin, 1); } @@ -1162,19 +1367,19 @@ smp_wake_up_non_boot_cpus() ensured via another rendez-vous) the variable can be reset. */ void -smp_cpu_rendezvous(volatile uint32* var, int current_cpu) +smp_cpu_rendezvous(uint32* var) { - atomic_or((vint32*)var, 1 << current_cpu); + atomic_add((int32*)var, 1); - while (*var != (((uint32)1 << sNumCPUs) - 1)) - PAUSE(); + while (atomic_get((int32*)var) < sNumCPUs) + cpu_wait((int32*)var, sNumCPUs); } status_t smp_init(kernel_args* args) { - TRACE(("smp_init: entry\n")); + TRACE("smp_init: entry\n"); #if DEBUG_SPINLOCK_LATENCIES sEnableLatencyCheck @@ -1213,7 +1418,7 @@ smp_init(kernel_args* args) } sNumCPUs = args->num_cpus; } - TRACE(("smp_init: calling arch_smp_init\n")); + TRACE("smp_init: calling arch_smp_init\n"); return arch_smp_init(args); } @@ -1310,15 +1515,20 @@ call_all_cpus_sync(void (*func)(void*, int), void* cookie) } +#undef memory_read_barrier +#undef memory_write_barrier + + void -memory_read_barrier(void) +memory_read_barrier() { - arch_cpu_memory_read_barrier(); + memory_read_barrier_inline(); } void -memory_write_barrier(void) +memory_write_barrier() { - arch_cpu_memory_write_barrier(); + memory_write_barrier_inline(); } + diff --git a/src/system/kernel/system_info.cpp b/src/system/kernel/system_info.cpp index a97cdcad10..5fa166436e 100644 --- a/src/system/kernel/system_info.cpp +++ b/src/system/kernel/system_info.cpp @@ -1,10 +1,11 @@ /* - * Copyright (c) 2004-2010, Haiku, Inc. + * Copyright (c) 2004-2013, Haiku, Inc. * Distributed under the terms of the MIT license. * * Authors: * Stefano Ceccherini * Axel Dörfler, axeld@pinc-software.de + * Paweł Dziepak, pdziepak@quarnos.org * Ingo Weinhold, ingo_weinhold@gmx.de */ @@ -16,6 +17,8 @@ #include +#include + #include #include @@ -50,10 +53,12 @@ dump_info(int argc, char **argv) __VERSION__); kprintf("revision: %s\n\n", get_haiku_revision()); - kprintf("cpu count: %" B_PRId32 ", active times:\n", smp_get_num_cpus()); + kprintf("cpu count: %" B_PRId32 "\n", smp_get_num_cpus()); for (int32 i = 0; i < smp_get_num_cpus(); i++) - kprintf(" [%" B_PRId32 "] %" B_PRId64 "\n", i + 1, gCPU[i].active_time); + kprintf(" [%" B_PRId32 "] active time: %10" B_PRId64 ", interrupt" + " time: %10" B_PRId64 ", irq time: %10" B_PRId64 "\n", i + 1, + gCPU[i].active_time, gCPU[i].interrupt_time, gCPU[i].irq_time); // ToDo: Add page_faults kprintf("pages:\t\t%" B_PRIuPHYSADDR " (%" B_PRIuPHYSADDR " max)\n", @@ -405,21 +410,15 @@ SystemNotificationService::Listener::OwnerDeleted(AssociatedDataOwner* owner) status_t -_get_system_info(system_info *info, size_t size) +get_system_info(system_info* info) { - if (size != sizeof(system_info)) - return B_BAD_VALUE; - memset(info, 0, sizeof(system_info)); info->boot_time = rtc_boot_time(); info->cpu_count = smp_get_num_cpus(); - for (int32 i = 0; i < info->cpu_count; i++) - info->cpu_infos[i].active_time = cpu_get_active_time(i); - vm_page_get_stats(info); - // TODO: Add page_faults + vm_get_info(info); info->used_threads = thread_used_threads(); info->max_threads = thread_max_threads(); @@ -436,11 +435,31 @@ _get_system_info(system_info *info, size_t size) strlcpy(info->kernel_build_time, __TIME__, B_OS_NAME_LENGTH); info->abi = B_HAIKU_ABI; - // all other stuff is architecture specific - return arch_get_system_info(info, size); + return B_OK; } +status_t +get_cpu_info(uint32 firstCPU, uint32 cpuCount, cpu_info* info) +{ + if (firstCPU >= (uint32)smp_get_num_cpus()) + return B_BAD_VALUE; + if (cpuCount == 0) + return B_OK; + + uint32 count = std::min(cpuCount, smp_get_num_cpus() - firstCPU); + + memset(info, 0, sizeof(cpu_info) * count); + for (uint32 i = 0; i < count; i++) { + info[i].active_time = cpu_get_active_time(firstCPU + i); + info[i].enabled = !gCPU[firstCPU + i].disabled; + } + + return B_OK; +} + + + status_t system_info_init(struct kernel_args *args) { @@ -469,15 +488,13 @@ system_notifications_init() status_t -_user_get_system_info(system_info *userInfo, size_t size) +_user_get_system_info(system_info* userInfo) { - // The BeBook says get_system_info() always returns B_OK, - // but that ain't true with invalid addresses if (userInfo == NULL || !IS_USER_ADDRESS(userInfo)) return B_BAD_ADDRESS; system_info info; - status_t status = _get_system_info(&info, size); + status_t status = get_system_info(&info); if (status == B_OK) { if (user_memcpy(userInfo, &info, sizeof(system_info)) < B_OK) return B_BAD_ADDRESS; @@ -490,28 +507,119 @@ _user_get_system_info(system_info *userInfo, size_t size) status_t -_user_get_system_info_etc(int32 id, void* userInfo, size_t size) +_user_get_cpu_info(uint32 firstCPU, uint32 cpuCount, cpu_info* userInfo) { if (userInfo == NULL || !IS_USER_ADDRESS(userInfo)) return B_BAD_ADDRESS; + if (firstCPU >= (uint32)smp_get_num_cpus()) + return B_BAD_VALUE; + if (cpuCount == 0) + return B_OK; - switch (id) { - case B_MEMORY_INFO: - { - if (size < sizeof(system_memory_info)) - return B_BAD_VALUE; + uint32 count = std::min(cpuCount, smp_get_num_cpus() - firstCPU); - system_memory_info info; - vm_get_info(&info); + cpu_info* cpuInfos = new(std::nothrow) cpu_info[count]; + if (cpuInfos == NULL) + return B_NO_MEMORY; + ArrayDeleter _(cpuInfos); - info.block_cache_memory = block_cache_used_memory(); + status_t error = get_cpu_info(firstCPU, count, cpuInfos); + if (error != B_OK) + return error; - return user_memcpy(userInfo, &info, sizeof(system_memory_info)); - } + return user_memcpy(userInfo, cpuInfos, sizeof(cpu_info) * count); +} - default: - return B_BAD_VALUE; + +static void +count_topology_nodes(const cpu_topology_node* node, uint32& count) +{ + count++; + for (int32 i = 0; i < node->children_count; i++) + count_topology_nodes(node->children[i], count); +} + + +static int32 +get_logical_processor(const cpu_topology_node* node) +{ + while (node->level != CPU_TOPOLOGY_SMT) { + ASSERT(node->children_count > 0); + node = node->children[0]; } + + return node->id; +} + + +static cpu_topology_node_info* +generate_topology_array(cpu_topology_node_info* topology, + const cpu_topology_node* node, uint32& count) +{ + if (count == 0) + return topology; + + static const topology_level_type mapTopologyLevels[] = { B_TOPOLOGY_SMT, + B_TOPOLOGY_CORE, B_TOPOLOGY_PACKAGE, B_TOPOLOGY_ROOT }; + + STATIC_ASSERT(sizeof(mapTopologyLevels) / sizeof(topology_level_type) + == CPU_TOPOLOGY_LEVELS + 1); + + topology->id = node->id; + topology->level = node->level; + topology->type = mapTopologyLevels[node->level]; + + arch_fill_topology_node(topology, get_logical_processor(node)); + + count--; + topology++; + for (int32 i = 0; i < node->children_count && count > 0; i++) + topology = generate_topology_array(topology, node->children[i], count); + return topology; +} + + +status_t +_user_get_cpu_topology_info(cpu_topology_node_info* topologyInfos, + uint32* topologyInfoCount) +{ + if (topologyInfoCount == NULL || !IS_USER_ADDRESS(topologyInfoCount)) + return B_BAD_ADDRESS; + + const cpu_topology_node* node = get_cpu_topology(); + + uint32 count = 0; + count_topology_nodes(node, count); + + if (topologyInfos == NULL) + return user_memcpy(topologyInfoCount, &count, sizeof(uint32)); + else if (!IS_USER_ADDRESS(topologyInfoCount)) + return B_BAD_ADDRESS; + + uint32 userCount; + status_t error = user_memcpy(&userCount, topologyInfoCount, sizeof(uint32)); + if (error != B_OK) + return error; + if (userCount == 0) + return B_OK; + count = std::min(count, userCount); + + cpu_topology_node_info* topology + = new(std::nothrow) cpu_topology_node_info[count]; + if (topology == NULL) + return B_NO_MEMORY; + ArrayDeleter _(topology); + memset(topology, 0, sizeof(cpu_topology_node_info) * count); + + uint32 nodesLeft = count; + generate_topology_array(topology, node, nodesLeft); + ASSERT(nodesLeft == 0); + + error = user_memcpy(topologyInfos, topology, + sizeof(cpu_topology_node_info) * count); + if (error != B_OK) + return error; + return user_memcpy(topologyInfoCount, &count, sizeof(uint32)); } diff --git a/src/system/kernel/team.cpp b/src/system/kernel/team.cpp index 44ddacf5d5..dfa50c70b3 100644 --- a/src/system/kernel/team.cpp +++ b/src/system/kernel/team.cpp @@ -494,6 +494,9 @@ Team::Team(team_id id, bool kernel) // init dead/stopped/continued children condition vars dead_children.condition_variable.Init(&dead_children, "team children"); + B_INITIALIZE_SPINLOCK(&time_lock); + B_INITIALIZE_SPINLOCK(&signal_lock); + fQueuedSignalsCounter = new(std::nothrow) BKernel::QueuedSignalsCounter( kernel ? -1 : MAX_QUEUED_SIGNALS); memset(fSignalActions, 0, sizeof(fSignalActions)); @@ -910,7 +913,7 @@ Team::DeactivateCPUTimeUserTimers() /*! Returns the team's current total CPU time (kernel + user + offset). - The caller must hold the scheduler lock. + The caller must hold \c time_lock. \param ignoreCurrentRun If \c true and the current thread is one team's threads, don't add the time since the last time \c last_time was @@ -933,7 +936,7 @@ Team::CPUTime(bool ignoreCurrentRun) const SpinLocker threadTimeLocker(thread->time_lock); time += thread->kernel_time + thread->user_time; - if (thread->IsRunning()) { + if (thread->last_time != 0) { if (!ignoreCurrentRun || thread != currentThread) time += now - thread->last_time; } @@ -945,7 +948,7 @@ Team::CPUTime(bool ignoreCurrentRun) const /*! Returns the team's current user CPU time. - The caller must hold the scheduler lock. + The caller must hold \c time_lock. \return The team's current user CPU time. */ @@ -961,7 +964,7 @@ Team::UserCPUTime() const SpinLocker threadTimeLocker(thread->time_lock); time += thread->user_time; - if (thread->IsRunning() && !thread->in_kernel) + if (thread->last_time != 0 && !thread->in_kernel) time += now - thread->last_time; } @@ -1807,11 +1810,13 @@ load_image_internal(char**& _flatArgs, size_t flatArgsSize, int32 argCount, // wait for the loader of the new team to finish its work if ((flags & B_WAIT_TILL_LOADED) != 0) { - InterruptsSpinLocker schedulerLocker(gSchedulerLock); + if (mainThread != NULL) { + InterruptsSpinLocker schedulerLocker(mainThread->scheduler_lock); - // resume the team's main thread - if (mainThread != NULL && mainThread->state == B_THREAD_SUSPENDED) - scheduler_enqueue_in_run_queue(mainThread); + // resume the team's main thread + if (mainThread->state == B_THREAD_SUSPENDED) + scheduler_enqueue_in_run_queue(mainThread); + } // Now suspend ourselves until loading is finished. We will be woken // either by the thread, when it finished or aborted loading, or when @@ -1819,11 +1824,11 @@ load_image_internal(char**& _flatArgs, size_t flatArgsSize, int32 argCount, // setting `loadingInfo.done' is responsible for removing the info from // the team structure. while (!loadingInfo.done) { - thread_get_current_thread()->next_state = B_THREAD_SUSPENDED; - scheduler_reschedule(); - } + Thread* thread = thread_get_current_thread(); - schedulerLocker.Unlock(); + InterruptsSpinLocker schedulerLocker(thread->scheduler_lock); + scheduler_reschedule(B_THREAD_SUSPENDED); + } if (loadingInfo.result < B_OK) return loadingInfo.result; @@ -2460,7 +2465,7 @@ wait_for_child(pid_t child, uint32 flags, siginfo_t& _info) } else { // The child is well. Reset its job control state. team_set_job_control_state(entry->team, - JOB_CONTROL_STATE_NONE, NULL, false); + JOB_CONTROL_STATE_NONE, NULL); } } } @@ -2547,14 +2552,16 @@ wait_for_child(pid_t child, uint32 flags, siginfo_t& _info) // If SIGCHLD is blocked, we shall clear pending SIGCHLDs, if no other child // status is available. TeamLocker teamLocker(team); - InterruptsSpinLocker schedulerLocker(gSchedulerLock); + InterruptsSpinLocker signalLocker(team->signal_lock); + SpinLocker threadCreationLocker(gThreadCreationLock); if (is_team_signal_blocked(team, SIGCHLD)) { if (get_job_control_entry(team, child, flags) == NULL) team->RemovePendingSignals(SIGNAL_TO_MASK(SIGCHLD)); } - schedulerLocker.Unlock(); + threadCreationLocker.Unlock(); + signalLocker.Unlock(); teamLocker.Unlock(); // When the team is dead, the main thread continues to live in the kernel @@ -2941,12 +2948,12 @@ team_set_foreground_process_group(int32 ttyIndex, pid_t processGroupID) if (session->foreground_group != -1 && session->foreground_group != team->group_id && team->SignalActionFor(SIGTTOU).sa_handler != SIG_IGN) { - InterruptsSpinLocker schedulerLocker(gSchedulerLock); + InterruptsSpinLocker signalLocker(team->signal_lock); if (!is_team_signal_blocked(team, SIGTTOU)) { pid_t groupID = team->group_id; - schedulerLocker.Unlock(); + signalLocker.Unlock(); sessionLocker.Unlock(); teamLocker.Unlock(); @@ -3110,12 +3117,12 @@ team_shutdown_team(Team* team) team->DeleteUserTimers(false); // deactivate CPU time user timers for the team - InterruptsSpinLocker schedulerLocker(gSchedulerLock); + InterruptsSpinLocker timeLocker(team->time_lock); if (team->HasActiveCPUTimeUserTimers()) team->DeactivateCPUTimeUserTimers(); - schedulerLocker.Unlock(); + timeLocker.Unlock(); // kill all threads but the main thread team_death_entry deathEntry; @@ -3186,7 +3193,7 @@ team_delete_team(Team* team, port_id debuggerPort) loadingInfo->result = B_ERROR; loadingInfo->done = true; - InterruptsSpinLocker schedulerLocker(gSchedulerLock); + InterruptsSpinLocker _(loadingInfo->thread->scheduler_lock); // wake up the waiting thread if (loadingInfo->thread->state == B_THREAD_SUSPENDED) @@ -3272,8 +3279,7 @@ team_get_address_space(team_id id, VMAddressSpace** _addressSpace) /*! Sets the team's job control state. The caller must hold the parent team's lock. Interrupts are allowed to be - enabled or disabled. In the latter case the scheduler lock may be held as - well. + enabled or disabled. \a team The team whose job control state shall be set. \a newState The new state to be set. \a signal The signal the new state was caused by. Can \c NULL, if none. Then @@ -3282,11 +3288,10 @@ team_get_address_space(team_id id, VMAddressSpace** _addressSpace) \c JOB_CONTROL_STATE_NONE: - \c signal: The number of the signal causing the state change. - \c signaling_user: The real UID of the user sending the signal. - \a schedulerLocked indicates whether the scheduler lock is being held, too. */ void team_set_job_control_state(Team* team, job_control_state newState, - Signal* signal, bool schedulerLocked) + Signal* signal) { if (team == NULL || team->job_control_entry == NULL) return; @@ -3342,8 +3347,7 @@ team_set_job_control_state(Team* team, job_control_state newState, if (childList != NULL) { childList->entries.Add(entry); - team->parent->dead_children.condition_variable.NotifyAll( - schedulerLocked); + team->parent->dead_children.condition_variable.NotifyAll(); } } @@ -4103,7 +4107,7 @@ _user_setpgid(pid_t processID, pid_t groupID) // Changing the process group might have changed the situation for a // parent waiting in wait_for_child(). Hence we notify it. - team->parent->dead_children.condition_variable.NotifyAll(false); + team->parent->dead_children.condition_variable.NotifyAll(); return group->id; } @@ -4145,7 +4149,7 @@ _user_setsid(void) // Changing the process group might have changed the situation for a // parent waiting in wait_for_child(). Hence we notify it. - team->parent->dead_children.condition_variable.NotifyAll(false); + team->parent->dead_children.condition_variable.NotifyAll(); return group->id; } diff --git a/src/system/kernel/thread.cpp b/src/system/kernel/thread.cpp index 7e29df2927..6f9d4da1c9 100644 --- a/src/system/kernel/thread.cpp +++ b/src/system/kernel/thread.cpp @@ -70,7 +70,7 @@ typedef BKernel::TeamThreadTable ThreadHashTable; // thread list -static Thread sIdleThreads[B_MAX_CPU_COUNT]; +static Thread sIdleThreads[SMP_MAX_CPUS]; static ThreadHashTable sThreadHash; static spinlock sThreadHashLock = B_SPINLOCK_INITIALIZER; static thread_id sNextThreadID = 2; @@ -81,6 +81,8 @@ static thread_id sNextThreadID = 2; static int32 sMaxThreads = 4096; static int32 sUsedThreads = 0; +spinlock gThreadCreationLock = B_SPINLOCK_INITIALIZER; + struct UndertakerEntry : DoublyLinkedListLinkImpl { Thread* thread; @@ -141,6 +143,7 @@ public: static DoublyLinkedList sUndertakerEntries; +static spinlock sUndertakerLock = B_SPINLOCK_INITIALIZER; static ConditionVariable sUndertakerCondition; static ThreadNotificationService sNotificationService; @@ -165,9 +168,7 @@ Thread::Thread(const char* name, thread_id threadID, struct cpu_ent* cpu) serial_number(-1), hash_next(NULL), team_next(NULL), - queue_next(NULL), priority(-1), - next_priority(-1), io_priority(-1), cpu(cpu), previous_cpu(NULL), @@ -179,7 +180,7 @@ Thread::Thread(const char* name, thread_id threadID, struct cpu_ent* cpu) signal_stack_size(0), signal_stack_enabled(false), in_kernel(true), - was_yielded(false), + has_yielded(false), user_thread(NULL), fault_handler(0), page_faults_allowed(1), @@ -207,6 +208,8 @@ Thread::Thread(const char* name, thread_id threadID, struct cpu_ent* cpu) mutex_init_etc(&fLock, lockName, MUTEX_FLAG_CLONE_NAME); B_INITIALIZE_SPINLOCK(&time_lock); + B_INITIALIZE_SPINLOCK(&scheduler_lock); + B_INITIALIZE_RW_SPINLOCK(&team_lock); // init name if (name != NULL) @@ -214,8 +217,6 @@ Thread::Thread(const char* name, thread_id threadID, struct cpu_ent* cpu) else strcpy(this->name, "unnamed thread"); - alarm.period = 0; - exit.status = 0; list_init(&exit.waiters); @@ -697,21 +698,10 @@ common_thread_entry(void* _args) // The thread is new and has been scheduled the first time. - // start CPU time based user timers - if (thread->HasActiveCPUTimeUserTimers() - || thread->team->HasActiveCPUTimeUserTimers()) { - user_timer_continue_cpu_timers(thread, thread->cpu->previous_thread); - } - - // notify the user debugger code - if ((thread->flags & THREAD_FLAGS_DEBUGGER_INSTALLED) != 0) - user_debug_thread_scheduled(thread); - - // start tracking time - thread->last_time = system_time(); + scheduler_new_thread_entry(thread); // unlock the scheduler lock and enable interrupts - release_spinlock(&gSchedulerLock); + release_spinlock(&thread->scheduler_lock); enable_interrupts(); // call the kernel function, if any @@ -901,9 +891,7 @@ thread_create_thread(const ThreadCreationAttributes& attributes, bool kernel) // available for deinitialization thread->priority = attributes.priority == -1 ? B_NORMAL_PRIORITY : attributes.priority; - thread->next_priority = thread->priority; thread->state = B_THREAD_SUSPENDED; - thread->next_state = B_THREAD_SUSPENDED; thread->sig_block_mask = attributes.signal_mask; @@ -1019,7 +1007,8 @@ thread_create_thread(const ThreadCreationAttributes& attributes, bool kernel) // for our own use (and threadReference remains armed). ThreadLocker threadLocker(thread); - InterruptsSpinLocker schedulerLocker(gSchedulerLock); + + InterruptsSpinLocker threadCreationLocker(gThreadCreationLock); SpinLocker threadHashLocker(sThreadHashLock); // check the thread limit @@ -1027,7 +1016,7 @@ thread_create_thread(const ThreadCreationAttributes& attributes, bool kernel) // 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(); + threadCreationLocker.Unlock(); user_thread* userThread = thread->user_thread; thread->user_thread = NULL; @@ -1043,6 +1032,7 @@ thread_create_thread(const ThreadCreationAttributes& attributes, bool kernel) // make thread visible in global hash/list thread->visible = true; sUsedThreads++; + scheduler_on_thread_init(thread); thread->AcquireReference(); @@ -1059,11 +1049,16 @@ thread_create_thread(const ThreadCreationAttributes& attributes, bool kernel) } } - // insert thread into team - insert_thread_into_team(team, thread); + { + SpinLocker signalLocker(team->signal_lock); + SpinLocker timeLocker(team->time_lock); + + // insert thread into team + insert_thread_into_team(team, thread); + } threadHashLocker.Unlock(); - schedulerLocker.Unlock(); + threadCreationLocker.Unlock(); threadLocker.Unlock(); teamLocker.Unlock(); @@ -1079,20 +1074,20 @@ undertaker(void* /*args*/) { while (true) { // wait for a thread to bury - InterruptsSpinLocker schedulerLocker(gSchedulerLock); + InterruptsSpinLocker locker(sUndertakerLock); while (sUndertakerEntries.IsEmpty()) { ConditionVariableEntry conditionEntry; sUndertakerCondition.Add(&conditionEntry); - schedulerLocker.Unlock(); + locker.Unlock(); conditionEntry.Wait(); - schedulerLocker.Lock(); + locker.Lock(); } UndertakerEntry* _entry = sUndertakerEntries.RemoveHead(); - schedulerLocker.Unlock(); + locker.Unlock(); UndertakerEntry entry = *_entry; // we need a copy, since the original entry is on the thread's stack @@ -1100,16 +1095,27 @@ undertaker(void* /*args*/) // we've got an entry Thread* thread = entry.thread; + // make sure the thread isn't running anymore + InterruptsSpinLocker schedulerLocker(thread->scheduler_lock); + ASSERT(thread->state == THREAD_STATE_FREE_ON_RESCHED); + schedulerLocker.Unlock(); + // remove this thread from from the kernel team -- this makes it // unaccessible Team* kernelTeam = team_get_kernel_team(); TeamLocker kernelTeamLocker(kernelTeam); thread->Lock(); - schedulerLocker.Lock(); + + InterruptsSpinLocker threadCreationLocker(gThreadCreationLock); + SpinLocker signalLocker(kernelTeam->signal_lock); + SpinLocker timeLocker(kernelTeam->time_lock); remove_thread_from_team(kernelTeam, thread); - schedulerLocker.Unlock(); + timeLocker.Unlock(); + signalLocker.Unlock(); + threadCreationLocker.Unlock(); + kernelTeamLocker.Unlock(); // free the thread structure @@ -1366,11 +1372,9 @@ common_snooze_etc(bigtime_t timeout, clockid_t clockID, uint32 flags, Thread* thread = thread_get_current_thread(); - InterruptsSpinLocker schedulerLocker(gSchedulerLock); - thread_prepare_to_block(thread, flags, THREAD_BLOCK_TYPE_SNOOZE, NULL); - status_t status = thread_block_with_timeout_locked(flags, timeout); + status_t status = thread_block_with_timeout(flags, timeout); if (status == B_TIMED_OUT || status == B_WOULD_BLOCK) return B_OK; @@ -1427,7 +1431,7 @@ make_thread_unreal(int argc, char **argv) continue; if (thread->priority > B_DISPLAY_PRIORITY) { - thread->priority = thread->next_priority = B_NORMAL_PRIORITY; + scheduler_set_thread_priority(thread, B_NORMAL_PRIORITY); kprintf("thread %" B_PRId32 " made unreal\n", thread->id); } } @@ -1463,7 +1467,7 @@ set_thread_prio(int argc, char **argv) Thread* thread = it.Next();) { if (thread->id != id) continue; - thread->priority = thread->next_priority = prio; + scheduler_set_thread_priority(thread, prio); kprintf("thread %" B_PRId32 " set to priority %" B_PRId32 "\n", id, prio); found = true; break; @@ -1496,7 +1500,9 @@ make_thread_suspended(int argc, char **argv) if (thread->id != id) continue; - thread->next_state = B_THREAD_SUSPENDED; + Signal signal(SIGSTOP, SI_USER, B_OK, team_get_kernel_team()->id); + send_signal_to_thread(thread, signal, B_DO_NOT_RESCHEDULE); + kprintf("thread %" B_PRId32 " suspended\n", id); found = true; break; @@ -1700,13 +1706,11 @@ _dump_thread_info(Thread *thread, bool shortInfo) thread->id); kprintf("serial_number: %" B_PRId64 "\n", thread->serial_number); kprintf("name: \"%s\"\n", thread->name); - kprintf("hash_next: %p\nteam_next: %p\nq_next: %p\n", - thread->hash_next, thread->team_next, thread->queue_next); - kprintf("priority: %" B_PRId32 " (next %" B_PRId32 ", " - "I/O: %" B_PRId32 ")\n", thread->priority, thread->next_priority, - thread->io_priority); + kprintf("hash_next: %p\nteam_next: %p\n", + thread->hash_next, thread->team_next); + kprintf("priority: %" B_PRId32 " (I/O: %" B_PRId32 ")\n", + thread->priority, thread->io_priority); kprintf("state: %s\n", state_to_text(thread, thread->state)); - kprintf("next_state: %s\n", state_to_text(thread, thread->next_state)); kprintf("cpu: %p ", thread->cpu); if (thread->cpu) kprintf("(%d)\n", thread->cpu->cpu_num); @@ -1788,6 +1792,8 @@ _dump_thread_info(Thread *thread, bool shortInfo) kprintf("flags: 0x%" B_PRIx32 "\n", thread->flags); kprintf("architecture dependant section:\n"); arch_thread_dump_info(&thread->arch_info); + kprintf("scheduler data:\n"); + scheduler_dump_thread_data(thread); } @@ -1919,17 +1925,9 @@ thread_exit(void) panic("thread_exit() called with interrupts disabled!\n"); // boost our priority to get this over with - thread->priority = thread->next_priority = B_URGENT_DISPLAY_PRIORITY; + scheduler_set_thread_priority(thread, B_URGENT_DISPLAY_PRIORITY); if (team != kernelTeam) { - // Cancel previously installed alarm timer, if any. Hold the scheduler - // lock to make sure that when cancel_timer() returns, the alarm timer - // hook will not be invoked anymore (since - // B_TIMER_ACQUIRE_SCHEDULER_LOCK is used). - InterruptsSpinLocker schedulerLocker(gSchedulerLock); - cancel_timer(&thread->alarm); - schedulerLocker.Unlock(); - // Delete all user timers associated with the thread. ThreadLocker threadLocker(thread); thread->DeleteUserTimers(false); @@ -1991,16 +1989,20 @@ thread_exit(void) // swap address spaces, to make sure we're running on the kernel's pgdir vm_swap_address_space(team->address_space, VMAddressSpace::Kernel()); - SpinLocker schedulerLocker(gSchedulerLock); + WriteSpinLocker teamLocker(thread->team_lock); + SpinLocker threadCreationLocker(gThreadCreationLock); // removing the thread and putting its death entry to the parent // team needs to be an atomic operation // remember how long this thread lasted bigtime_t now = system_time(); - InterruptsSpinLocker threadTimeLocker(thread->time_lock); + + InterruptsSpinLocker signalLocker(kernelTeam->signal_lock); + SpinLocker teamTimeLocker(kernelTeam->time_lock); + SpinLocker threadTimeLocker(thread->time_lock); + thread->kernel_time += now - thread->last_time; thread->last_time = now; - threadTimeLocker.Unlock(); team->dead_threads_kernel_time += thread->kernel_time; team->dead_threads_user_time += thread->user_time; @@ -2015,13 +2017,20 @@ thread_exit(void) if (thread->HasActiveCPUTimeUserTimers()) thread->DeactivateCPUTimeUserTimers(); + threadTimeLocker.Unlock(); + // put the thread into the kernel team until it dies remove_thread_from_team(team, thread); insert_thread_into_team(kernelTeam, thread); + teamTimeLocker.Unlock(); + signalLocker.Unlock(); + + teamLocker.Unlock(); + if (team->death_entry != NULL) { if (--team->death_entry->remaining_threads == 0) - team->death_entry->condition.NotifyOne(true, B_OK); + team->death_entry->condition.NotifyOne(); } if (deleteTeam) { @@ -2029,8 +2038,7 @@ thread_exit(void) // Set the team job control state to "dead" and detach the job // control entry from our team struct. - team_set_job_control_state(team, JOB_CONTROL_STATE_DEAD, NULL, - true); + team_set_job_control_state(team, JOB_CONTROL_STATE_DEAD, NULL); death = team->job_control_entry; team->job_control_entry = NULL; @@ -2047,7 +2055,7 @@ thread_exit(void) death = NULL; } - schedulerLocker.Unlock(); + threadCreationLocker.Unlock(); restore_interrupts(state); threadLocker.Unlock(); @@ -2110,7 +2118,7 @@ thread_exit(void) } } - schedulerLocker.Unlock(); + threadCreationLocker.Unlock(); restore_interrupts(state); threadLocker.Unlock(); @@ -2135,7 +2143,7 @@ thread_exit(void) ThreadLocker threadLocker(thread); state = disable_interrupts(); - SpinLocker schedulerLocker(gSchedulerLock); + SpinLocker threadCreationLocker(gThreadCreationLock); // mark invisible in global hash/list, so it's no longer accessible SpinLocker threadHashLocker(sThreadHashLock); @@ -2153,7 +2161,7 @@ thread_exit(void) select_info* selectInfos = thread->select_infos; thread->select_infos = NULL; - schedulerLocker.Unlock(); + threadCreationLocker.Unlock(); restore_interrupts(state); threadLocker.Unlock(); @@ -2234,13 +2242,15 @@ thread_exit(void) UndertakerEntry undertakerEntry(thread, teamID); disable_interrupts(); - schedulerLocker.Lock(); + SpinLocker schedulerLocker(thread->scheduler_lock); + + SpinLocker undertakerLocker(sUndertakerLock); sUndertakerEntries.Add(&undertakerEntry); - sUndertakerCondition.NotifyOne(true); + sUndertakerCondition.NotifyOne(); + undertakerLocker.Unlock(); - thread->next_state = THREAD_STATE_FREE_ON_RESCHED; - scheduler_reschedule(); + scheduler_reschedule(THREAD_STATE_FREE_ON_RESCHED); panic("never can get here\n"); } @@ -2336,75 +2346,11 @@ thread_reset_for_exec(void) thread->user_stack_size = 0; // reset signals - InterruptsSpinLocker schedulerLocker(gSchedulerLock); - thread->ResetSignalsOnExec(); // reset thread CPU time clock + InterruptsSpinLocker timeLocker(thread->time_lock); thread->cpu_clock_offset = -thread->CPUTime(false); - - // Note: We don't cancel an alarm. It is supposed to survive exec*(). -} - - -/*! Insert a thread to the tail of a queue */ -void -thread_enqueue(Thread *thread, struct thread_queue *queue) -{ - thread->queue_next = NULL; - if (queue->head == NULL) { - queue->head = thread; - queue->tail = thread; - } else { - queue->tail->queue_next = thread; - queue->tail = thread; - } -} - - -Thread * -thread_lookat_queue(struct thread_queue *queue) -{ - return queue->head; -} - - -Thread * -thread_dequeue(struct thread_queue *queue) -{ - Thread *thread = queue->head; - - if (thread != NULL) { - queue->head = thread->queue_next; - if (queue->tail == thread) - queue->tail = NULL; - } - return thread; -} - - -Thread * -thread_dequeue_id(struct thread_queue *q, thread_id id) -{ - Thread *thread; - Thread *last = NULL; - - thread = q->head; - while (thread != NULL) { - if (thread->id == id) { - if (last == NULL) - q->head = thread->queue_next; - else - last->queue_next = thread->queue_next; - - if (q->tail == thread) - q->tail = last; - break; - } - last = thread; - thread = thread->queue_next; - } - return thread; } @@ -2438,39 +2384,32 @@ peek_next_thread_id() /*! Yield the CPU to other threads. - If \a force is \c true, the thread will almost guaranteedly be unscheduled. - If \c false, it will continue to run, if there's no other thread in ready + Thread will continue to run, if there's no other thread in ready state, and if it has a higher priority than the other ready threads, it still has a good chance to continue. */ void -thread_yield(bool force) +thread_yield(void) { - if (force) { - // snooze for roughly 3 thread quantums - snooze_etc(9000, B_SYSTEM_TIMEBASE, B_RELATIVE_TIMEOUT | B_CAN_INTERRUPT); -#if 0 - cpu_status state; + Thread *thread = thread_get_current_thread(); + if (thread == NULL) + return; - Thread *thread = thread_get_current_thread(); - if (thread == NULL) - return; + InterruptsSpinLocker _(thread->scheduler_lock); - InterruptsSpinLocker _(gSchedulerLock); + thread->has_yielded = true; + scheduler_reschedule(B_THREAD_READY); +} - // mark the thread as yielded, so it will not be scheduled next - //thread->was_yielded = true; - thread->next_priority = B_LOWEST_ACTIVE_PRIORITY; - scheduler_reschedule(); -#endif - } else { - Thread *thread = thread_get_current_thread(); - if (thread == NULL) - return; - // Don't force the thread off the CPU, just reschedule. - InterruptsSpinLocker _(gSchedulerLock); - scheduler_reschedule(); +void +thread_map(void (*function)(Thread* thread, void* data), void* data) +{ + InterruptsSpinLocker threadHashLocker(sThreadHashLock); + + for (ThreadHashTable::Iterator it = sThreadHash.GetIterator(); + Thread* thread = it.Next();) { + function(thread, data); } } @@ -2679,7 +2618,6 @@ thread_get_io_priority(thread_id id) int32 priority = thread->io_priority; if (priority < 0) { // negative I/O priority means using the (CPU) priority - InterruptsSpinLocker schedulerLocker(gSchedulerLock); priority = thread->priority; } @@ -2737,9 +2675,8 @@ thread_init(kernel_args *args) gCPU[i].running_thread = thread; thread->team = team_get_kernel_team(); - thread->priority = thread->next_priority = B_IDLE_PRIORITY; + thread->priority = B_IDLE_PRIORITY; thread->state = B_THREAD_RUNNING; - thread->next_state = B_THREAD_READY; sprintf(name, "idle thread %" B_PRIu32 " kstack", i + 1); thread->kernel_stack_area = find_area(name); @@ -2751,6 +2688,8 @@ thread_init(kernel_args *args) thread->visible = true; insert_thread_into_team(thread->team, thread); + + scheduler_on_thread_init(thread); } sUsedThreads = args->num_cpus; @@ -2857,17 +2796,44 @@ thread_preboot_init_percpu(struct kernel_args *args, int32 cpuNum) static status_t thread_block_timeout(timer* timer) { - // The timer has been installed with B_TIMER_ACQUIRE_SCHEDULER_LOCK, so - // we're holding the scheduler lock already. This makes things comfortably - // easy. - Thread* thread = (Thread*)timer->user_data; - thread_unblock_locked(thread, B_TIMED_OUT); + thread_unblock(thread, B_TIMED_OUT); return B_HANDLED_INTERRUPT; } +/*! Blocks the current thread. + + The thread is blocked until someone else unblock it. Must be called after a + call to thread_prepare_to_block(). If the thread has already been unblocked + after the previous call to thread_prepare_to_block(), this function will + return immediately. Cf. the documentation of thread_prepare_to_block() for + more details. + + The caller must hold the scheduler lock. + + \param thread The current thread. + \return The error code passed to the unblocking function. thread_interrupt() + uses \c B_INTERRUPTED. By convention \c B_OK means that the wait was + successful while another error code indicates a failure (what that means + depends on the client code). +*/ +static inline status_t +thread_block_locked(Thread* thread) +{ + if (thread->wait.status == 1) { + // check for signals, if interruptible + if (thread_is_interrupted(thread, thread->wait.flags)) { + thread->wait.status = B_INTERRUPTED; + } else + scheduler_reschedule(B_THREAD_WAITING); + } + + return thread->wait.status; +} + + /*! Blocks the current thread. The function acquires the scheduler lock and calls thread_block_locked(). @@ -2876,24 +2842,11 @@ thread_block_timeout(timer* timer) status_t thread_block() { - InterruptsSpinLocker _(gSchedulerLock); + InterruptsSpinLocker _(thread_get_current_thread()->scheduler_lock); return thread_block_locked(thread_get_current_thread()); } -/*! Blocks the current thread with a timeout. - - Acquires the scheduler lock and calls thread_block_with_timeout_locked(). - See there for more information. -*/ -status_t -thread_block_with_timeout(uint32 timeoutFlags, bigtime_t timeout) -{ - InterruptsSpinLocker _(gSchedulerLock); - return thread_block_with_timeout_locked(timeoutFlags, timeout); -} - - /*! Blocks the current thread with a timeout. The thread is blocked until someone else unblock it or the specified timeout @@ -2902,7 +2855,7 @@ thread_block_with_timeout(uint32 timeoutFlags, bigtime_t timeout) thread_prepare_to_block(), this function will return immediately. See thread_prepare_to_block() for more details. - The caller must hold the scheduler lock. + The caller must not hold the scheduler lock. \param thread The current thread. \param timeoutFlags The standard timeout flags: @@ -2922,10 +2875,12 @@ thread_block_with_timeout(uint32 timeoutFlags, bigtime_t timeout) client code). */ status_t -thread_block_with_timeout_locked(uint32 timeoutFlags, bigtime_t timeout) +thread_block_with_timeout(uint32 timeoutFlags, bigtime_t timeout) { Thread* thread = thread_get_current_thread(); + InterruptsSpinLocker locker(thread->scheduler_lock); + if (thread->wait.status != 1) return thread->wait.status; @@ -2933,10 +2888,7 @@ thread_block_with_timeout_locked(uint32 timeoutFlags, bigtime_t timeout) && timeout != B_INFINITE_TIMEOUT; if (useTimer) { - // Timer flags: absolute/relative + "acquire thread lock". The latter - // avoids nasty race conditions and deadlock problems that could - // otherwise occur between our cancel_timer() and a concurrently - // executing thread_block_timeout(). + // Timer flags: absolute/relative. uint32 timerFlags; if ((timeoutFlags & B_RELATIVE_TIMEOUT) != 0) { timerFlags = B_ONE_SHOT_RELATIVE_TIMER; @@ -2945,7 +2897,6 @@ thread_block_with_timeout_locked(uint32 timeoutFlags, bigtime_t timeout) if ((timeoutFlags & B_TIMEOUT_REAL_TIME_BASE) != 0) timerFlags |= B_TIMER_REAL_TIME_BASE; } - timerFlags |= B_TIMER_ACQUIRE_SCHEDULER_LOCK; // install the timer thread->wait.unblock_timer.user_data = thread; @@ -2956,6 +2907,8 @@ thread_block_with_timeout_locked(uint32 timeoutFlags, bigtime_t timeout) // block status_t error = thread_block_locked(thread); + locker.Unlock(); + // cancel timer, if it didn't fire if (error != B_TIMED_OUT && useTimer) cancel_timer(&thread->wait.unblock_timer); @@ -2964,6 +2917,19 @@ thread_block_with_timeout_locked(uint32 timeoutFlags, bigtime_t timeout) } +/*! Unblocks a thread. + + Acquires the scheduler lock and calls thread_unblock_locked(). + See there for more information. +*/ +void +thread_unblock(Thread* thread, status_t status) +{ + InterruptsSpinLocker locker(thread->scheduler_lock); + thread_unblock_locked(thread, status); +} + + /*! Unblocks a userland-blocked thread. The caller must not hold any locks. */ @@ -2980,7 +2946,7 @@ user_unblock_thread(thread_id threadID, status_t status) if (thread->user_thread == NULL) return B_NOT_ALLOWED; - InterruptsSpinLocker schedulerLocker(gSchedulerLock); + InterruptsSpinLocker locker(thread->scheduler_lock); if (thread->user_thread->wait_status > 0) { thread->user_thread->wait_status = status; @@ -3083,7 +3049,7 @@ _get_thread_info(thread_id id, thread_info *info, size_t size) ThreadLocker threadLocker(thread, true); // fill the info -- also requires the scheduler lock to be held - InterruptsSpinLocker schedulerLocker(gSchedulerLock); + InterruptsSpinLocker locker(thread->scheduler_lock); fill_thread_info(thread, info, size); @@ -3133,7 +3099,7 @@ _get_next_thread_info(team_id teamID, int32 *_cookie, thread_info *info, *_cookie = lastID; ThreadLocker threadLocker(thread); - InterruptsSpinLocker schedulerLocker(gSchedulerLock); + InterruptsSpinLocker locker(thread->scheduler_lock); fill_thread_info(thread, info, size); @@ -3199,8 +3165,6 @@ rename_thread(thread_id id, const char* name) status_t set_thread_priority(thread_id id, int32 priority) { - int32 oldPriority; - // make sure the passed in priority is within bounds if (priority > THREAD_MAX_SET_PRIORITY) priority = THREAD_MAX_SET_PRIORITY; @@ -3218,19 +3182,7 @@ set_thread_priority(thread_id id, int32 priority) if (thread_is_idle_thread(thread)) return B_NOT_ALLOWED; - InterruptsSpinLocker schedulerLocker(gSchedulerLock); - - if (thread == thread_get_current_thread()) { - // It's ourself, so we know we aren't in the run queue, and we can - // manipulate our structure directly. - oldPriority = thread->priority; - thread->priority = thread->next_priority = priority; - } else { - oldPriority = thread->priority; - scheduler_set_thread_priority(thread, priority); - } - - return oldPriority; + return scheduler_set_thread_priority(thread, priority); } @@ -3372,7 +3324,8 @@ _user_cancel_thread(thread_id threadID, void (*cancelFunction)(int)) thread->cancel_function = cancelFunction; // send the cancellation signal to the thread - InterruptsSpinLocker schedulerLocker(gSchedulerLock); + InterruptsReadSpinLocker teamLocker(thread->team_lock); + SpinLocker locker(thread->team->signal_lock); return send_signal_to_thread_locked(thread, SIGNAL_CANCEL_THREAD, NULL, 0); } @@ -3522,7 +3475,7 @@ _user_snooze_etc(bigtime_t timeout, int timebase, uint32 flags, void _user_thread_yield(void) { - thread_yield(true); + thread_yield(); } @@ -3663,11 +3616,9 @@ _user_block_thread(uint32 flags, bigtime_t timeout) thread_prepare_to_block(thread, flags, THREAD_BLOCK_TYPE_OTHER, "user"); threadLocker.Unlock(); - InterruptsSpinLocker schedulerLocker(gSchedulerLock); - status_t status = thread_block_with_timeout_locked(flags, timeout); + status_t status = thread_block_with_timeout(flags, timeout); - schedulerLocker.Unlock(); threadLocker.Lock(); // Interruptions or timeouts can race with other threads unblocking us. diff --git a/src/system/kernel/timer.cpp b/src/system/kernel/timer.cpp index 3f626c9eeb..28284f4ae1 100644 --- a/src/system/kernel/timer.cpp +++ b/src/system/kernel/timer.cpp @@ -29,11 +29,11 @@ struct per_cpu_timer_data { spinlock lock; timer* volatile events; timer* volatile current_event; - vint32 current_event_in_progress; + int32 current_event_in_progress; bigtime_t real_time_offset; }; -static per_cpu_timer_data sPerCPU[B_MAX_CPU_COUNT]; +static per_cpu_timer_data sPerCPU[SMP_MAX_CPUS]; //#define TRACE_TIMER @@ -264,7 +264,7 @@ timer_interrupt() cpuData.events = (timer*)event->next; cpuData.current_event = event; - cpuData.current_event_in_progress = 1; + atomic_set(&cpuData.current_event_in_progress, 1); release_spinlock(spinlock); @@ -274,27 +274,10 @@ timer_interrupt() // call the callback // note: if the event is not periodic, it is ok // to delete the event structure inside the callback - if (event->hook) { - bool callHook = true; + if (event->hook) + rc = event->hook(event); - // we may need to acquire the scheduler lock - if ((mode & B_TIMER_ACQUIRE_SCHEDULER_LOCK) != 0) { - acquire_spinlock(&gSchedulerLock); - - // If the event has been cancelled in the meantime, we don't - // call the hook anymore. - if (cpuData.current_event == NULL) - callHook = false; - } - - if (callHook) - rc = event->hook(event); - - if ((mode & B_TIMER_ACQUIRE_SCHEDULER_LOCK) != 0) - release_spinlock(&gSchedulerLock); - } - - cpuData.current_event_in_progress = 0; + atomic_set(&cpuData.current_event_in_progress, 0); acquire_spinlock(spinlock); @@ -400,7 +383,7 @@ cancel_timer(timer* event) int cpu = event->cpu; SpinLocker spinLocker; while (true) { - if (cpu >= B_MAX_CPU_COUNT) + if (cpu >= SMP_MAX_CPUS) return false; spinLocker.SetTo(sPerCPU[cpu].lock, false); @@ -461,13 +444,11 @@ cancel_timer(timer* event) // lock to be held while calling the event hook, we'll have to wait // for the hook to complete. When called from the timer hook we don't // wait either, of course. - if ((event->flags & B_TIMER_ACQUIRE_SCHEDULER_LOCK) == 0 - && cpu != smp_get_current_cpu()) { + if (cpu != smp_get_current_cpu()) { spinLocker.Unlock(); - while (cpuData.current_event_in_progress == 1) { - PAUSE(); - } + while (atomic_get(&cpuData.current_event_in_progress) == 1) + cpu_wait(&cpuData.current_event_in_progress, 0); } return true; @@ -479,7 +460,6 @@ spin(bigtime_t microseconds) { bigtime_t time = system_time(); - while ((system_time() - time) < microseconds) { - PAUSE(); - } + while ((system_time() - time) < microseconds) + cpu_pause(); } diff --git a/src/system/kernel/usergroup.cpp b/src/system/kernel/usergroup.cpp index 5a54ea07c9..9be52f5a0c 100644 --- a/src/system/kernel/usergroup.cpp +++ b/src/system/kernel/usergroup.cpp @@ -54,7 +54,6 @@ common_setregid(gid_t rgid, gid_t egid, bool setAllIfPrivileged, bool kernel) // setgid() semantics: If privileged set both, real, effective and // saved set-gid, otherwise set the effective gid. if (privileged) { - InterruptsSpinLocker schedulerLocker(gSchedulerLock); team->saved_set_gid = rgid; team->real_gid = rgid; team->effective_gid = rgid; @@ -91,7 +90,6 @@ common_setregid(gid_t rgid, gid_t egid, bool setAllIfPrivileged, bool kernel) } // Getting here means all checks were successful -- set the gids. - InterruptsSpinLocker schedulerLocker(gSchedulerLock); team->real_gid = rgid; team->effective_gid = egid; team->saved_set_gid = ssgid; @@ -119,7 +117,6 @@ common_setreuid(uid_t ruid, uid_t euid, bool setAllIfPrivileged, bool kernel) // setuid() semantics: If privileged set both, real, effective and // saved set-uid, otherwise set the effective uid. if (privileged) { - InterruptsSpinLocker schedulerLocker(gSchedulerLock); team->saved_set_uid = ruid; team->real_uid = ruid; team->effective_uid = ruid; @@ -156,7 +153,6 @@ common_setreuid(uid_t ruid, uid_t euid, bool setAllIfPrivileged, bool kernel) } // Getting here means all checks were successful -- set the uids. - InterruptsSpinLocker schedulerLocker(gSchedulerLock); team->real_uid = ruid; team->effective_uid = euid; team->saved_set_uid = ssuid; @@ -253,8 +249,6 @@ common_setgroups(int groupCount, const gid_t* groupList, bool kernel) void inherit_parent_user_and_group(Team* team, Team* parent) { - InterruptsSpinLocker schedulerLocker(gSchedulerLock); - team->saved_set_uid = parent->saved_set_uid; team->real_uid = parent->real_uid; team->effective_uid = parent->effective_uid; @@ -262,8 +256,6 @@ inherit_parent_user_and_group(Team* team, Team* parent) team->real_gid = parent->real_gid; team->effective_gid = parent->effective_gid; - schedulerLocker.Unlock(); - malloc_referenced_acquire(parent->supplementary_groups); team->supplementary_groups = parent->supplementary_groups; team->supplementary_group_count = parent->supplementary_group_count; @@ -279,7 +271,6 @@ update_set_id_user_and_group(Team* team, const char* file) return status; TeamLocker teamLocker(team); - InterruptsSpinLocker schedulerLocker(gSchedulerLock); if ((st.st_mode & S_ISUID) != 0) { team->saved_set_uid = st.st_uid; @@ -300,8 +291,6 @@ _kern_getgid(bool effective) { Team* team = thread_get_current_thread()->team; - InterruptsSpinLocker schedulerLocker(gSchedulerLock); - return effective ? team->effective_gid : team->real_gid; } @@ -311,8 +300,6 @@ _kern_getuid(bool effective) { Team* team = thread_get_current_thread()->team; - InterruptsSpinLocker schedulerLocker(gSchedulerLock); - return effective ? team->effective_uid : team->real_uid; } @@ -353,8 +340,6 @@ _user_getgid(bool effective) { Team* team = thread_get_current_thread()->team; - TeamLocker teamLocker(team); - return effective ? team->effective_gid : team->real_gid; } @@ -364,8 +349,6 @@ _user_getuid(bool effective) { Team* team = thread_get_current_thread()->team; - TeamLocker teamLocker(team); - return effective ? team->effective_uid : team->real_uid; } @@ -395,12 +378,9 @@ ssize_t _user_setgroups(int groupCount, const gid_t* groupList) { // check privilege - { - Team* team = thread_get_current_thread()->team; - TeamLocker teamLocker(team); - if (!is_privileged(team)) - return EPERM; - } + Team* team = thread_get_current_thread()->team; + if (!is_privileged(team)) + return EPERM; return common_setgroups(groupCount, groupList, false); } diff --git a/src/system/kernel/util/Bitmap.cpp b/src/system/kernel/util/Bitmap.cpp new file mode 100644 index 0000000000..8f47c95e19 --- /dev/null +++ b/src/system/kernel/util/Bitmap.cpp @@ -0,0 +1,68 @@ +/* + * Copyright 2013 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ + + +#include + +#include + +#include + +#include + + +const int Bitmap::kBitsPerElement = sizeof(addr_t) * 8; + + +Bitmap::Bitmap(int bitCount) + : + fInitStatus(B_OK), + fElementsCount(0), + fSize(bitCount) +{ + int count = fSize + kBitsPerElement - 1; + count /= kBitsPerElement; + + fBits = new(std::nothrow) addr_t[count]; + if (fBits == NULL) { + fSize = 0; + fInitStatus = B_NO_MEMORY; + } + + fElementsCount = count; + memset(fBits, 0, sizeof(addr_t) * count); +} + + +Bitmap::~Bitmap() +{ + delete[] fBits; +} + + +int +Bitmap::GetHighestSet() const +{ + int i = fElementsCount - 1; + while (i >= 0 && fBits[i] == 0) + i--; + + if (i < 0) + return -1; + + STATIC_ASSERT(sizeof(addr_t) == sizeof(uint64) + || sizeof(addr_t) == sizeof(uint32)); + if (sizeof(addr_t) == sizeof(uint32)) + return log2(fBits[i]) + i * kBitsPerElement; + + uint32 v = (uint64)fBits[i] >> 32; + if (v != 0) + return log2(v) + sizeof(uint32) * 8 + i * kBitsPerElement; + return log2(fBits[i]) + i * kBitsPerElement; +} + diff --git a/src/system/kernel/util/Jamfile b/src/system/kernel/util/Jamfile index cb8bf52853..42fa42e0fe 100644 --- a/src/system/kernel/util/Jamfile +++ b/src/system/kernel/util/Jamfile @@ -4,6 +4,7 @@ UsePrivateHeaders [ FDirName kernel util ] ; KernelMergeObject kernel_util.o : AVLTreeBase.cpp + Bitmap.cpp hostname.cpp inet_addr.c inet_ntop.c diff --git a/src/system/kernel/util/Random.cpp b/src/system/kernel/util/Random.cpp index 12a2eeb074..c4de06a0f9 100644 --- a/src/system/kernel/util/Random.cpp +++ b/src/system/kernel/util/Random.cpp @@ -109,7 +109,7 @@ random_value() unsigned int secure_random_value() { - static vint32 count = 0; + static int32 count = 0; uint32 data[8]; data[0] = atomic_add(&count, 1); diff --git a/src/system/kernel/vm/VMAnonymousCache.cpp b/src/system/kernel/vm/VMAnonymousCache.cpp index 7d3c0d8106..ff399c1aff 100644 --- a/src/system/kernel/vm/VMAnonymousCache.cpp +++ b/src/system/kernel/vm/VMAnonymousCache.cpp @@ -1667,11 +1667,11 @@ swap_total_swap_pages() void -swap_get_info(struct system_memory_info* info) +swap_get_info(system_info* info) { #if ENABLE_SWAP_SUPPORT - info->max_swap_space = (uint64)swap_total_swap_pages() * B_PAGE_SIZE; - info->free_swap_space = (uint64)swap_available_pages() * B_PAGE_SIZE; + info->max_swap_pages = swap_total_swap_pages(); + info->free_swap_pages = swap_available_pages(); #else info->max_swap_space = 0; info->free_swap_space = 0; diff --git a/src/system/kernel/vm/VMAnonymousCache.h b/src/system/kernel/vm/VMAnonymousCache.h index 065f422325..b68800047c 100644 --- a/src/system/kernel/vm/VMAnonymousCache.h +++ b/src/system/kernel/vm/VMAnonymousCache.h @@ -99,7 +99,7 @@ private: #endif // ENABLE_SWAP_SUPPORT -extern "C" void swap_get_info(struct system_memory_info* info); +extern "C" void swap_get_info(system_info* info); #endif /* _KERNEL_VM_STORE_ANONYMOUS_H */ diff --git a/src/system/kernel/vm/VMCache.cpp b/src/system/kernel/vm/VMCache.cpp index 62c2e70e06..688f5cb62f 100644 --- a/src/system/kernel/vm/VMCache.cpp +++ b/src/system/kernel/vm/VMCache.cpp @@ -1383,8 +1383,7 @@ VMCache::_NotifyPageEvents(vm_page* page, uint32 events) if (waiter->page == page && (waiter->events & events) != 0) { // remove from list and unblock *it = waiter->next; - InterruptsSpinLocker schedulerLocker(gSchedulerLock); - thread_unblock_locked(waiter->thread, B_OK); + thread_unblock(waiter->thread, B_OK); } else it = &waiter->next; } diff --git a/src/system/kernel/vm/vm.cpp b/src/system/kernel/vm/vm.cpp index 1d6de03466..d700fe5e52 100644 --- a/src/system/kernel/vm/vm.cpp +++ b/src/system/kernel/vm/vm.cpp @@ -4782,16 +4782,13 @@ vm_put_physical_page_debug(addr_t vaddr, void* handle) void -vm_get_info(system_memory_info* info) +vm_get_info(system_info* info) { swap_get_info(info); - info->max_memory = vm_page_num_pages() * B_PAGE_SIZE; - info->page_faults = sPageFaults; - MutexLocker locker(sAvailableMemoryLock); - info->free_memory = sAvailableMemory; info->needed_memory = sNeededMemory; + info->free_memory = sAvailableMemory; } diff --git a/src/system/kernel/vm/vm_page.cpp b/src/system/kernel/vm/vm_page.cpp index a08d8f53f7..a29eba47c2 100644 --- a/src/system/kernel/vm/vm_page.cpp +++ b/src/system/kernel/vm/vm_page.cpp @@ -119,9 +119,9 @@ static page_num_t sNonExistingPages; static uint64 sIgnoredPages; // pages of physical memory ignored by the boot loader (and thus not // available here) -static vint32 sUnreservedFreePages; -static vint32 sUnsatisfiedPageReservations; -static vint32 sModifiedTemporaryPages; +static int32 sUnreservedFreePages; +static int32 sUnsatisfiedPageReservations; +static int32 sModifiedTemporaryPages; static ConditionVariable sFreePageCondition; static mutex sPageDeficitLock = MUTEX_INITIALIZER("page deficit"); @@ -1407,7 +1407,7 @@ static uint32 reserve_some_pages(uint32 count, uint32 dontTouch) { while (true) { - int32 freePages = sUnreservedFreePages; + int32 freePages = atomic_get(&sUnreservedFreePages); if (freePages <= (int32)dontTouch) return 0; @@ -1447,8 +1447,7 @@ wake_up_page_reservation_waiters() sPageReservationWaiters.Remove(waiter); - InterruptsSpinLocker schedulerLocker(gSchedulerLock); - thread_unblock_locked(waiter->thread, B_OK); + thread_unblock(waiter->thread, B_OK); } } @@ -1457,7 +1456,7 @@ static inline void unreserve_pages(uint32 count) { atomic_add(&sUnreservedFreePages, count); - if (sUnsatisfiedPageReservations != 0) + if (atomic_get(&sUnsatisfiedPageReservations) != 0) wake_up_page_reservation_waiters(); } @@ -1745,7 +1744,8 @@ page_scrubber(void *unused) snooze(100000); // 100ms if (sFreePageQueue.Count() == 0 - || sUnreservedFreePages < (int32)sFreePagesTarget) { + || atomic_get(&sUnreservedFreePages) + < (int32)sFreePagesTarget) { continue; } @@ -1881,7 +1881,7 @@ private: uint32 fMaxPages; uint32 fWrapperCount; uint32 fTransferCount; - vint32 fPendingTransfers; + int32 fPendingTransfers; PageWriteWrapper* fWrappers; PageWriteTransfer* fTransfers; ConditionVariable fAllFinishedCondition; @@ -2207,7 +2207,7 @@ PageWriterRun::AddPage(vm_page* page) uint32 PageWriterRun::Go() { - fPendingTransfers = fTransferCount; + atomic_set(&fPendingTransfers, fTransferCount); fAllFinishedCondition.Init(this, "page writer wait for I/O"); ConditionVariableEntry waitEntry; @@ -2390,7 +2390,7 @@ page_writer(void* /*unused*/) if (cache->AcquireUnreferencedStoreRef() != B_OK) { DEBUG_PAGE_ACCESS_END(page); cacheLocker.Unlock(); - thread_yield(true); + thread_yield(); continue; } @@ -3006,7 +3006,7 @@ reserve_pages(uint32 count, int priority, bool dontWait) bool notifyDaemon = sUnsatisfiedPageReservations == 0; sUnsatisfiedPageReservations += count; - if (sUnreservedFreePages > dontTouch) { + if (atomic_get(&sUnreservedFreePages) > dontTouch) { // the situation changed sUnsatisfiedPageReservations -= count; continue; @@ -4065,6 +4065,7 @@ vm_page_get_stats(system_info *info) // TODO: We should subtract the blocks that are in use ATM, since those // can't really be freed in a low memory situation. page_num_t blockCachePages = block_cache_used_memory() / B_PAGE_SIZE; + info->block_cache_pages = blockCachePages; // Non-temporary modified pages are special as they represent pages that // can be written back, so they could be freed if necessary, for us @@ -4082,7 +4083,7 @@ vm_page_get_stats(system_info *info) // active + inactive + unused + wired + modified + cached + free + clear // So taking out the cached (including modified non-temporary), free and // clear ones leaves us with all used pages. - int32 subtractPages = info->cached_pages + sFreePageQueue.Count() + uint32 subtractPages = info->cached_pages + sFreePageQueue.Count() + sClearPageQueue.Count(); info->used_pages = subtractPages > info->max_pages ? 0 : info->max_pages - subtractPages; diff --git a/src/system/libroot/libroot_init.c b/src/system/libroot/libroot_init.c index 867cbd25a6..caef95b2fc 100644 --- a/src/system/libroot/libroot_init.c +++ b/src/system/libroot/libroot_init.c @@ -32,6 +32,7 @@ int __libc_argc; char **__libc_argv; int __gABIVersion; +int32 __gCPUCount; char _single_threaded = true; // determines if I/O locking needed; needed for BeOS compatibility @@ -48,6 +49,7 @@ int _data_offset_main_; void initialize_before(image_id imageID) { + system_info info; char *programPath = __gRuntimeLoader->program_args->args[0]; __gCommPageAddress = __gRuntimeLoader->commpage_address; __gABIVersion = __gRuntimeLoader->abi_version; @@ -70,6 +72,9 @@ initialize_before(image_id imageID) pthread_self()->id = find_thread(NULL); + get_system_info(&info); + __gCPUCount = info.cpu_count; + __init_time((addr_t)__gCommPageAddress); __init_heap(); __init_env(__gRuntimeLoader->program_args); diff --git a/src/system/libroot/os/Jamfile b/src/system/libroot/os/Jamfile index 1b2b30ce18..b27301252c 100644 --- a/src/system/libroot/os/Jamfile +++ b/src/system/libroot/os/Jamfile @@ -33,7 +33,7 @@ for architectureObject in [ MultiArchSubDirSetup ] { port.c scheduler.c sem.c - system_info.c + system_info.cpp system_revision.c team.c thread.c diff --git a/src/system/libroot/os/arch/x86/atomic.S b/src/system/libroot/os/arch/x86/atomic.S index 31b46f1b06..9e26dfde79 100644 --- a/src/system/libroot/os/arch/x86/atomic.S +++ b/src/system/libroot/os/arch/x86/atomic.S @@ -1,4 +1,7 @@ /* + * Copyright 2013, Paweł Dziepak, pdziepak@quarnos.org. + * Distributed under the terms of the MIT License. + * ** Copyright 2003, Marcus Overhagen. All rights reserved. ** Distributed under the terms of the OpenBeOS license. ** @@ -6,96 +9,133 @@ ** Distributed under the terms of the NewOS License. */ + #include .text -/* int32 atomic_set(vint32 *value, int32 newValue) */ + +/* void atomic_set(int32* value, int32 newValue) */ FUNCTION(atomic_set): - movl 4(%esp),%edx - movl 8(%esp),%eax + movl 4(%esp), %edx + movl 8(%esp), %eax lock - xchg %eax,(%edx) + addl $0, (%esp) + movl %eax, (%edx) ret FUNCTION_END(atomic_set) -/* int32 atomic_test_and_set(vint32 *value, int32 newValue, int32 testAgainst) */ + +/* int32 atomic_get_and_set(int32* value, int32 newValue) */ +FUNCTION(atomic_get_and_set): + movl 4(%esp), %edx + movl 8(%esp), %eax + xchg %eax, (%edx) + ret +FUNCTION_END(atomic_get_and_set) + + +/* int32 atomic_test_and_set(int32* value, int32 newValue, + int32 testAgainst) */ FUNCTION(atomic_test_and_set): - movl 4(%esp),%edx - movl 8(%esp),%ecx - movl 12(%esp),%eax + movl 4(%esp), %edx + movl 8(%esp), %ecx + movl 12(%esp), %eax lock - cmpxchgl %ecx,(%edx) + cmpxchgl %ecx, (%edx) ret FUNCTION_END(atomic_test_and_set) -/* int32 atomic_add(vint32 *value, int32 addValue) */ + +/* int32 atomic_add(int32* value, int32 addValue) */ FUNCTION(atomic_add): - movl 4(%esp),%edx - movl 8(%esp),%eax + movl 4(%esp), %edx + movl 8(%esp), %eax lock - xaddl %eax,(%edx) + xaddl %eax, (%edx) ret FUNCTION_END(atomic_add) -/* int32 atomic_and(vint32 *value, int32 andValue) */ + +/* int32 atomic_and(int32* value, int32 andValue) */ FUNCTION(atomic_and): - movl 4(%esp),%edx -_atomic_and1: - movl 8(%esp),%ecx - movl (%edx),%eax - andl %eax,%ecx + movl 4(%esp), %edx +1: + movl 8(%esp), %ecx + movl (%edx), %eax + andl %eax, %ecx lock - cmpxchgl %ecx,(%edx) - jnz _atomic_and1 + cmpxchgl %ecx, (%edx) + jnz 1b ret FUNCTION_END(atomic_and) -/* int32 atomic_or(vint32 *value, int32 orValue) */ + +/* int32 atomic_or(int32* value, int32 orValue) */ FUNCTION(atomic_or): - movl 4(%esp),%edx -_atomic_or1: - movl 8(%esp),%ecx - movl (%edx),%eax - orl %eax,%ecx + movl 4(%esp), %edx +1: + movl 8(%esp), %ecx + movl (%edx), %eax + orl %eax, %ecx lock - cmpxchgl %ecx,(%edx) - jnz _atomic_or1 + cmpxchgl %ecx, (%edx) + jnz 1b ret FUNCTION_END(atomic_or) -/* int32 atomic_get(vint32 *value) */ + +/* int32 atomic_get(int32* value) */ FUNCTION(atomic_get): movl 4(%esp), %edx -_atomic_get1: movl (%edx), %eax - movl %eax, %ecx lock - cmpxchgl %ecx, (%edx) - jnz _atomic_get1 + addl $0, (%esp) ret FUNCTION_END(atomic_get) -/* int64 atomic_set64(vint64 *value, int64 newValue) */ + +/* void atomic_set64(int64* value, int64 newValue) */ FUNCTION(atomic_set64): push %esi push %ebx movl 12(%esp), %esi /* value */ movl 16(%esp), %ebx /* newValue low */ movl 20(%esp), %ecx /* newValue high */ -_atomic_set64_1: +1: movl (%esi), %eax /* testAgainst low */ movl 4(%esi), %edx /* testAgainst high */ lock cmpxchg8b (%esi) - jnz _atomic_set64_1 + jnz 1b pop %ebx pop %esi ret FUNCTION_END(atomic_set64) -/* int64 atomic_test_and_set64(vint64 *value, int64 newValue, int64 testAgainst) */ + +/* void atomic_get_and_set64(int64* value, int64 newValue) */ +FUNCTION(atomic_get_and_set64): + push %esi + push %ebx + movl 12(%esp), %esi /* value */ + movl 16(%esp), %ebx /* newValue low */ + movl 20(%esp), %ecx /* newValue high */ +1: + movl (%esi), %eax /* testAgainst low */ + movl 4(%esi), %edx /* testAgainst high */ + lock + cmpxchg8b (%esi) + jnz 1b + pop %ebx + pop %esi + ret +FUNCTION_END(atomic_get_and_set64) + + +/* int64 atomic_test_and_set64(int64* value, int64 newValue, + int64 testAgainst) */ FUNCTION(atomic_test_and_set64): push %esi push %ebx @@ -111,12 +151,13 @@ FUNCTION(atomic_test_and_set64): ret FUNCTION_END(atomic_test_and_set64) -/* int64 atomic_add64(vint64 *value, int64 addValue) */ + +/* int64 atomic_add64(int64* value, int64 addValue) */ FUNCTION(atomic_add64): push %esi push %ebx movl 12(%esp), %esi -_atomic_add64_1: +1: movl (%esi), %eax movl 4(%esi), %edx movl %eax, %ebx @@ -125,18 +166,18 @@ _atomic_add64_1: adcl 20(%esp), %ecx lock cmpxchg8b (%esi) - jnz _atomic_add64_1 + jnz 1b pop %ebx pop %esi ret FUNCTION_END(atomic_add64) -/* int64 atomic_and64(vint64 *value, int64 andValue) */ +/* int64 atomic_and64(int64* value, int64 andValue) */ FUNCTION(atomic_and64): push %esi push %ebx movl 12(%esp), %esi -_atomic_and64_1: +1: movl (%esi), %eax movl 4(%esi), %edx movl %eax, %ebx @@ -145,18 +186,19 @@ _atomic_and64_1: andl 20(%esp), %ecx lock cmpxchg8b (%esi) - jnz _atomic_and64_1 + jnz 1b pop %ebx pop %esi ret FUNCTION_END(atomic_and64) -/* int64 atomic_or64(vint64 *value, int64 orValue) */ + +/* int64 atomic_or64(int64* value, int64 orValue) */ FUNCTION(atomic_or64): push %esi push %ebx movl 12(%esp), %esi -_atomic_or64_1: +1: movl (%esi), %eax movl 4(%esi), %edx movl %eax, %ebx @@ -165,26 +207,28 @@ _atomic_or64_1: orl 20(%esp), %ecx lock cmpxchg8b (%esi) - jnz _atomic_or64_1 + jnz 1b pop %ebx pop %esi ret FUNCTION_END(atomic_or64) -/* int64 atomic_get64(vint64 *value) */ + +/* int64 atomic_get64(int64* value) */ FUNCTION(atomic_get64): push %esi push %ebx movl 12(%esp), %esi -_atomic_get64_1: +1: movl (%esi), %eax movl 4(%esi), %edx movl %eax, %ebx movl %edx, %ecx lock cmpxchg8b (%esi) - jnz _atomic_get64_1 + jnz 1b pop %ebx pop %esi ret FUNCTION_END(atomic_get64) + diff --git a/src/system/libroot/os/arch/x86_64/atomic.S b/src/system/libroot/os/arch/x86_64/atomic.S index 7abf2d2743..b88af32987 100644 --- a/src/system/libroot/os/arch/x86_64/atomic.S +++ b/src/system/libroot/os/arch/x86_64/atomic.S @@ -1,4 +1,5 @@ /* + * Copyright 2013, Paweł Dziepak, pdziepak@quarnos.org. * Copyright 2012, Alex Smith, alex@alex-smith.me.uk. * Distributed under the terms of the MIT License. */ @@ -9,15 +10,24 @@ .text -/* int32 atomic_set(vint32 *value, int32 newValue) */ + +/* int32 atomic_set(int32* value, int32 newValue) */ FUNCTION(atomic_set): - movl %esi, %eax - lock - xchgl %eax, (%rdi) + sfence + movl %esi, (%rdi) ret FUNCTION_END(atomic_set) -/* int32 atomic_test_and_set(vint32 *value, int32 newValue, int32 testAgainst) */ + +/* int32 atomic_get_and_set(int32* value, int32 newValue) */ +FUNCTION(atomic_get_and_set): + movl %esi, %eax + xchgl %eax, (%rdi) + ret +FUNCTION_END(atomic_get_and_set) + + +/* int32 atomic_test_and_set(int32* value, int32 newValue, int32 testAgainst) */ FUNCTION(atomic_test_and_set): movl %edx, %eax lock @@ -25,7 +35,8 @@ FUNCTION(atomic_test_and_set): ret FUNCTION_END(atomic_test_and_set) -/* int32 atomic_add(vint32 *value, int32 addValue) */ + +/* int32 atomic_add(int32* value, int32 addValue) */ FUNCTION(atomic_add): movl %esi, %eax lock @@ -33,7 +44,8 @@ FUNCTION(atomic_add): ret FUNCTION_END(atomic_add) -/* int32 atomic_and(vint32 *value, int32 andValue) */ + +/* int32 atomic_and(int32* value, int32 andValue) */ FUNCTION(atomic_and): movl (%rdi), %eax 1: movl %eax, %edx @@ -46,7 +58,8 @@ FUNCTION(atomic_and): ret FUNCTION_END(atomic_and) -/* int32 atomic_or(vint32 *value, int32 orValue) */ + +/* int32 atomic_or(int32* value, int32 orValue) */ FUNCTION(atomic_or): movl (%rdi), %eax 1: movl %eax, %edx @@ -59,24 +72,33 @@ FUNCTION(atomic_or): ret FUNCTION_END(atomic_or) -/* int32 atomic_get(vint32 *value) */ + +/* int32 atomic_get(int32* value) */ FUNCTION(atomic_get): movl (%rdi), %eax -1: lock - cmpxchgl %eax, (%rdi) - jnz 1b + lfence ret FUNCTION_END(atomic_get) -/* int64 atomic_set64(vint64 *value, int64 newValue) */ + +/* int64 atomic_set64(int64* value, int64 newValue) */ FUNCTION(atomic_set64): - movq %rsi, %rax - lock - xchgq %rax, (%rdi) + sfence + movq %rsi, (%rdi) ret FUNCTION_END(atomic_set64) -/* int64 atomic_test_and_set64(vint64 *value, int64 newValue, int64 testAgainst) */ + +/* int64 atomic_get_and_set64(int64* value, int64 newValue) */ +FUNCTION(atomic_get_and_set64): + movq %rsi, %rax + xchgq %rax, (%rdi) + ret +FUNCTION_END(atomic_get_and_set64) + + +/* int64 atomic_test_and_set64(int64* value, int64 newValue, + int64 testAgainst) */ FUNCTION(atomic_test_and_set64): movq %rdx, %rax lock @@ -84,7 +106,8 @@ FUNCTION(atomic_test_and_set64): ret FUNCTION_END(atomic_test_and_set64) -/* int64 atomic_add64(vint64 *value, int64 addValue) */ + +/* int64 atomic_add64(int64* value, int64 addValue) */ FUNCTION(atomic_add64): movq %rsi, %rax lock @@ -92,7 +115,8 @@ FUNCTION(atomic_add64): ret FUNCTION_END(atomic_add64) -/* int64 atomic_and64(vint64 *value, int64 andValue) */ + +/* int64 atomic_and64(int64* value, int64 andValue) */ FUNCTION(atomic_and64): movq (%rdi), %rax 1: movq %rax, %rdx @@ -105,7 +129,8 @@ FUNCTION(atomic_and64): ret FUNCTION_END(atomic_and64) -/* int64 atomic_or64(vint64 *value, int64 orValue) */ + +/* int64 atomic_or64(int64* value, int64 orValue) */ FUNCTION(atomic_or64): movq (%rdi), %rax 1: movq %rax, %rdx @@ -118,11 +143,11 @@ FUNCTION(atomic_or64): ret FUNCTION_END(atomic_or64) -/* int64 atomic_get64(vint64 *value) */ + +/* int64 atomic_get64(int64* value) */ FUNCTION(atomic_get64): movq (%rdi), %rax -1: lock - cmpxchgq %rax, (%rdi) - jnz 1b + lfence ret FUNCTION_END(atomic_get64) + diff --git a/src/system/libroot/os/locks/init_once.cpp b/src/system/libroot/os/locks/init_once.cpp index 2ec5e7e824..ce3ad18041 100644 --- a/src/system/libroot/os/locks/init_once.cpp +++ b/src/system/libroot/os/locks/init_once.cpp @@ -16,7 +16,7 @@ enum { status_t -__init_once(vint32* control, status_t (*initRoutine)(void*), void* data) +__init_once(int32* control, status_t (*initRoutine)(void*), void* data) { // Algorithm: // The control variable goes through at most four states: @@ -41,7 +41,7 @@ __init_once(vint32* control, status_t (*initRoutine)(void*), void* data) // we're the first -- perform the initialization initRoutine(data); - value = atomic_set(control, STATE_INITIALIZED); + value = atomic_get_and_set(control, STATE_INITIALIZED); // If someone else is waiting, we need to delete the semaphore. if (value >= 0) diff --git a/src/system/libroot/os/locks/mutex.cpp b/src/system/libroot/os/locks/mutex.cpp index 2e755bb9c2..93fca56d5f 100644 --- a/src/system/libroot/os/locks/mutex.cpp +++ b/src/system/libroot/os/locks/mutex.cpp @@ -18,6 +18,12 @@ #include +#define MAX_UNSUCCESSFUL_SPINS 100 + + +extern int32 __gCPUCount; + + // #pragma mark - mutex @@ -36,6 +42,9 @@ mutex_init_etc(mutex *lock, const char *name, uint32 flags) lock->name = (flags & MUTEX_FLAG_CLONE_NAME) != 0 ? strdup(name) : name; lock->lock = 0; lock->flags = flags; + + if (__gCPUCount < 2) + lock->flags &= ~uint32(MUTEX_FLAG_ADAPTIVE); } @@ -50,15 +59,22 @@ mutex_destroy(mutex *lock) status_t mutex_lock(mutex *lock) { - // set the locked flag - int32 oldValue = atomic_or(&lock->lock, B_USER_MUTEX_LOCKED); + uint32 count = 0; + const uint32 kMaxCount + = (lock->flags & MUTEX_FLAG_ADAPTIVE) != 0 ? MAX_UNSUCCESSFUL_SPINS : 1; - if ((oldValue & (B_USER_MUTEX_LOCKED | B_USER_MUTEX_WAITING)) == 0 - || (oldValue & B_USER_MUTEX_DISABLED) != 0) { - // No one has the lock or is waiting for it, or the mutex has been - // disabled. - return B_OK; - } + int32 oldValue; + do { + // set the locked flag + oldValue = atomic_or(&lock->lock, B_USER_MUTEX_LOCKED); + + if ((oldValue & (B_USER_MUTEX_LOCKED | B_USER_MUTEX_WAITING)) == 0 + || (oldValue & B_USER_MUTEX_DISABLED) != 0) { + // No one has the lock or is waiting for it, or the mutex has been + // disabled. + return B_OK; + } + } while (count++ < kMaxCount && (oldValue & B_USER_MUTEX_WAITING) != 0); // we have to call the kernel status_t error; diff --git a/src/system/libroot/os/scheduler.c b/src/system/libroot/os/scheduler.c index 65e9713c16..4dc16b6225 100644 --- a/src/system/libroot/os/scheduler.c +++ b/src/system/libroot/os/scheduler.c @@ -32,6 +32,9 @@ static struct { {(uint32)-1, -1} }; +status_t __set_scheduler_mode(int32 mode); +int32 __get_scheduler_mode(void); + int32 suggest_thread_priority(uint32 what, int32 period, bigtime_t jitter, @@ -60,3 +63,21 @@ estimate_max_scheduling_latency(thread_id thread) return _kern_estimate_max_scheduling_latency(thread); } + +status_t +__set_scheduler_mode(int32 mode) +{ + return _kern_set_scheduler_mode(mode); +} + + +int32 +__get_scheduler_mode(void) +{ + return _kern_get_scheduler_mode(); +} + + +B_DEFINE_WEAK_ALIAS(__set_scheduler_mode, set_scheduler_mode); +B_DEFINE_WEAK_ALIAS(__get_scheduler_mode, get_scheduler_mode); + diff --git a/src/system/libroot/os/system_info.c b/src/system/libroot/os/system_info.c deleted file mode 100644 index 0392337fda..0000000000 --- a/src/system/libroot/os/system_info.c +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2002-2008, Axel Dörfler, axeld@pinc-software.de. - * Distributed under the terms of the MIT License. - */ - - -#include - -#include -#include - - -status_t -_get_system_info(system_info *info, size_t size) -{ - if (info == NULL || size != sizeof(system_info)) - return B_BAD_VALUE; - - return _kern_get_system_info(info, size); -} - - -status_t -__get_system_info_etc(int32 id, void *info, size_t size) -{ - if (info == NULL || size == 0 || id < 0) - return B_BAD_VALUE; - - return _kern_get_system_info_etc(id, info, size); -} - - -status_t -__start_watching_system(int32 object, uint32 flags, port_id port, int32 token) -{ - return _kern_start_watching_system(object, flags, port, token); -} - - -status_t -__stop_watching_system(int32 object, uint32 flags, port_id port, int32 token) -{ - return _kern_stop_watching_system(object, flags, port, token); -} - - -int32 -is_computer_on(void) -{ - return _kern_is_computer_on(); -} - - -double -is_computer_on_fire(void) -{ - return 0.63739; -} - diff --git a/src/system/libroot/os/system_info.cpp b/src/system/libroot/os/system_info.cpp new file mode 100644 index 0000000000..337e7469a9 --- /dev/null +++ b/src/system/libroot/os/system_info.cpp @@ -0,0 +1,232 @@ +/* + * Copyright 2013, Paweł Dziepak, pdziepak@quarnos.org. + * Copyright 2002-2008, Axel Dörfler, axeld@pinc-software.de. + * Distributed under the terms of the MIT License. + */ + + +#include + +#include + +#include + +#include +#include + + +#if _BEOS_R5_COMPATIBLE_ + + +enum cpu_type { + B_CPU_PPC_601 = 1, + B_CPU_PPC_603 = 2, + B_CPU_PPC_603e = 3, + B_CPU_PPC_604 = 4, + B_CPU_PPC_604e = 5, + B_CPU_PPC_686 = 13, + B_CPU_AMD_29K, + B_CPU_X86, + B_CPU_MC6502, + B_CPU_Z80, + B_CPU_ALPHA, + B_CPU_MIPS, + B_CPU_HPPA, + B_CPU_M68K, + B_CPU_ARM, + B_CPU_SH, + B_CPU_SPARC +}; + +enum platform_type { + B_BEBOX_PLATFORM = 0, + B_MAC_PLATFORM, + B_AT_CLONE_PLATFORM, + B_ENIAC_PLATFORM, + B_APPLE_II_PLATFORM, + B_CRAY_PLATFORM, + B_LISA_PLATFORM, + B_TI_994A_PLATFORM, + B_TIMEX_SINCLAIR_PLATFORM, + B_ORAC_1_PLATFORM, + B_HAL_PLATFORM +}; + +typedef struct { + bigtime_t active_time; /* usec of doing useful work since boot */ +} legacy_cpu_info; + +typedef struct { + int32 id[2]; /* unique machine ID */ + bigtime_t boot_time; /* time of boot (usecs since 1/1/1970) */ + + int32 cpu_count; /* number of cpus */ + enum cpu_type cpu_type; /* type of cpu */ + int32 cpu_revision; /* revision # of cpu */ + legacy_cpu_info cpu_infos[8]; /* info about individual cpus */ + int64 cpu_clock_speed; /* processor clock speed (Hz) */ + int64 bus_clock_speed; /* bus clock speed (Hz) */ + enum platform_type platform_type; /* type of machine we're on */ + + int32 max_pages; /* total # of accessible pages */ + int32 used_pages; /* # of accessible pages in use */ + int32 page_faults; /* # of page faults */ + int32 max_sems; + int32 used_sems; + int32 max_ports; + int32 used_ports; + int32 max_threads; + int32 used_threads; + int32 max_teams; + int32 used_teams; + + char kernel_name[256]; + char kernel_build_date[32]; + char kernel_build_time[32]; + int64 kernel_version; + + bigtime_t _busy_wait_time; /* reserved for whatever */ + + int32 cached_pages; + uint32 abi; /* the system API */ + int32 ignored_pages; /* # of ignored/inaccessible pages */ + int32 pad; +} legacy_system_info; + + +extern "C" status_t +_get_system_info(legacy_system_info* info, size_t size) +{ + if (info == NULL || size != sizeof(legacy_system_info)) + return B_BAD_VALUE; + memset(info, 0, sizeof(legacy_system_info)); + + system_info systemInfo; + status_t error = _kern_get_system_info(&systemInfo); + if (error != B_OK) + return error; + + cpu_info cpuInfos[8]; + error = _kern_get_cpu_info(0, std::min(systemInfo.cpu_count, uint32(8)), + cpuInfos); + if (error != B_OK) + return error; + + info->boot_time = systemInfo.boot_time; + info->cpu_count = std::min(systemInfo.cpu_count, uint32(8)); + for (int32 i = 0; i < info->cpu_count; i++) + info->cpu_infos[i].active_time = cpuInfos[i].active_time; + + info->platform_type = B_AT_CLONE_PLATFORM; + info->cpu_type = B_CPU_X86; + + uint32 topologyNodeCount = 0; + cpu_topology_node_info* topology = NULL; + error = get_cpu_topology_info(NULL, &topologyNodeCount); + if (error != B_OK) + return B_OK; + if (topologyNodeCount != 0) { + topology = new(std::nothrow) cpu_topology_node_info[topologyNodeCount]; + if (topology == NULL) + return B_NO_MEMORY; + } + error = get_cpu_topology_info(topology, &topologyNodeCount); + if (error != B_OK) { + delete[] topology; + return error; + } + + for (uint32 i = 0; i < topologyNodeCount; i++) { + if (topology[i].type == B_TOPOLOGY_CORE) { + info->cpu_clock_speed = topology[i].data.core.default_frequency; + break; + } + } + info->bus_clock_speed = info->cpu_clock_speed; + delete[] topology; + + info->max_pages = std::min(systemInfo.max_pages, uint64(INT32_MAX)); + info->used_pages = std::min(systemInfo.used_pages, uint64(INT32_MAX)); + info->cached_pages = std::min(systemInfo.cached_pages, uint64(INT32_MAX)); + info->ignored_pages = std::min(systemInfo.ignored_pages, uint64(INT32_MAX)); + info->page_faults = std::min(systemInfo.page_faults, uint32(INT32_MAX)); + info->max_sems = std::min(systemInfo.max_sems, uint32(INT32_MAX)); + info->used_sems = std::min(systemInfo.used_sems, uint32(INT32_MAX)); + info->max_ports = std::min(systemInfo.max_ports, uint32(INT32_MAX)); + info->used_ports = std::min(systemInfo.used_ports, uint32(INT32_MAX)); + info->max_threads = std::min(systemInfo.max_threads, uint32(INT32_MAX)); + info->used_threads = std::min(systemInfo.used_threads, uint32(INT32_MAX)); + info->max_teams = std::min(systemInfo.max_teams, uint32(INT32_MAX)); + info->used_teams = std::min(systemInfo.used_teams, uint32(INT32_MAX)); + + strlcpy(info->kernel_name, systemInfo.kernel_name, + sizeof(info->kernel_name)); + strlcpy(info->kernel_build_date, systemInfo.kernel_build_date, + sizeof(info->kernel_build_date)); + strlcpy(info->kernel_build_time, systemInfo.kernel_build_time, + sizeof(info->kernel_build_time)); + info->kernel_version = systemInfo.kernel_version; + + info->abi = systemInfo.abi; + + return B_OK; +} + + +#endif + + +status_t +__get_system_info(system_info* info) +{ + return _kern_get_system_info(info); +} + + +status_t +__get_cpu_info(uint32 firstCPU, uint32 cpuCount, cpu_info* info) +{ + return _kern_get_cpu_info(firstCPU, cpuCount, info); +} + + +status_t +__get_cpu_topology_info(cpu_topology_node_info* topologyInfos, + uint32* topologyInfoCount) +{ + return _kern_get_cpu_topology_info(topologyInfos, topologyInfoCount); +} + + +status_t +__start_watching_system(int32 object, uint32 flags, port_id port, int32 token) +{ + return _kern_start_watching_system(object, flags, port, token); +} + + +status_t +__stop_watching_system(int32 object, uint32 flags, port_id port, int32 token) +{ + return _kern_stop_watching_system(object, flags, port, token); +} + + +int32 +is_computer_on(void) +{ + return _kern_is_computer_on(); +} + + +double +is_computer_on_fire(void) +{ + return 0.63739; +} + + +B_DEFINE_WEAK_ALIAS(__get_system_info, get_system_info); +B_DEFINE_WEAK_ALIAS(__get_cpu_info, get_cpu_info); +B_DEFINE_WEAK_ALIAS(__get_cpu_topology_info, get_cpu_topology_info); + diff --git a/src/system/libroot/posix/glibc/include/bits/libc-lock.h b/src/system/libroot/posix/glibc/include/bits/libc-lock.h index 5a1b5d1811..fc460360e4 100644 --- a/src/system/libroot/posix/glibc/include/bits/libc-lock.h +++ b/src/system/libroot/posix/glibc/include/bits/libc-lock.h @@ -19,7 +19,7 @@ extern char _single_threaded; static inline int __compare_and_swap (volatile int32 *p, int oldval, int newval) { - int32 readval = atomic_test_and_set(p, newval, oldval); + int32 readval = atomic_test_and_set((int32*)p, newval, oldval); return (readval == oldval ? 1 : 0); } diff --git a/src/system/libroot/posix/malloc/Jamfile b/src/system/libroot/posix/malloc/Jamfile index 3cb65cc7a0..9a14024dd2 100644 --- a/src/system/libroot/posix/malloc/Jamfile +++ b/src/system/libroot/posix/malloc/Jamfile @@ -1,6 +1,6 @@ SubDir HAIKU_TOP src system libroot posix malloc ; -UsePrivateHeaders libroot ; +UsePrivateHeaders libroot shared ; local architectureObject ; for architectureObject in [ MultiArchSubDirSetup ] { diff --git a/src/system/libroot/posix/malloc/arch-specific.cpp b/src/system/libroot/posix/malloc/arch-specific.cpp index 0f16100831..4b9572e868 100644 --- a/src/system/libroot/posix/malloc/arch-specific.cpp +++ b/src/system/libroot/posix/malloc/arch-specific.cpp @@ -41,12 +41,6 @@ void *(*sbrk_hook)(long) = &BPrivate::hoardSbrk; using namespace BPrivate; -// How many iterations we spin waiting for a lock. -enum { SPIN_LIMIT = 50 }; - -// The values of a user-level lock. -enum { UNLOCKED = 0, LOCKED = 1 }; - struct free_chunk { free_chunk *next; size_t size; @@ -368,35 +362,21 @@ hoardUnsbrk(void *ptr, long size) void hoardLockInit(hoardLockType &lock, const char *name) { - lock = UNLOCKED; + mutex_init_etc(&lock, name, MUTEX_FLAG_ADAPTIVE); } void hoardLock(hoardLockType &lock) { - // A yielding lock (with an initial spin). - while (true) { - int32 i = 0; - while (i < SPIN_LIMIT) { - if (atomic_test_and_set(&lock, LOCKED, UNLOCKED) == UNLOCKED) { - // We got the lock. - return; - } - i++; - } - - // The lock is still being held by someone else. - // Give up our quantum. - hoardYield(); - } + mutex_lock(&lock); } void hoardUnlock(hoardLockType &lock) { - atomic_set(&lock, UNLOCKED); + mutex_unlock(&lock); } diff --git a/src/system/libroot/posix/malloc/arch-specific.h b/src/system/libroot/posix/malloc/arch-specific.h index bffd92310f..88760c2e38 100644 --- a/src/system/libroot/posix/malloc/arch-specific.h +++ b/src/system/libroot/posix/malloc/arch-specific.h @@ -27,8 +27,12 @@ #include #include +#include -typedef int32 hoardLockType; + +// TODO: some kind of adaptive mutex (i.e. trying to spin for a while before +// may be a better choice +typedef mutex hoardLockType; namespace BPrivate { diff --git a/src/system/libroot/posix/malloc/heap.cpp b/src/system/libroot/posix/malloc/heap.cpp index 5ded94723e..99aba542d2 100644 --- a/src/system/libroot/posix/malloc/heap.cpp +++ b/src/system/libroot/posix/malloc/heap.cpp @@ -99,6 +99,7 @@ size_t hoardHeap::_threshold[hoardHeap::SIZE_CLASSES] = { #endif +int hoardHeap::fMaxThreadHeaps = 1; int hoardHeap::_numProcessors; int hoardHeap::_numProcessorsMask; @@ -454,7 +455,7 @@ hoardHeap::initNumProcs(void) else hoardHeap::_numProcessors = info.cpu_count; - hoardHeap::_numProcessorsMask = - (1 << (lg(hoardHeap::_numProcessors) + 1)) - 1; + fMaxThreadHeaps = 1 << (lg(_numProcessors) + 1); + _numProcessorsMask = fMaxThreadHeaps - 1; } diff --git a/src/system/libroot/posix/malloc/heap.h b/src/system/libroot/posix/malloc/heap.h index 9d0c51a6ea..b2a9ed6ba3 100644 --- a/src/system/libroot/posix/malloc/heap.h +++ b/src/system/libroot/posix/malloc/heap.h @@ -57,15 +57,6 @@ class hoardHeap { // empty. enum { MAX_EMPTY_SUPERBLOCKS = EMPTY_FRACTION }; - // The maximum number of thread heaps we allow. (NOT the maximum - // number of threads -- Hoard imposes no such limit.) This must be - // a power of two! NB: This number is twice the maximum number of - // PROCESSORS supported by Hoard. - enum { MAX_HEAPS = B_MAX_CPU_COUNT * 2 }; - - // ANDing with this rounds to MAX_HEAPS. - enum { MAX_HEAPS_MASK = MAX_HEAPS - 1 }; - // // The number of size classes. This combined with the // SIZE_CLASS_BASE determine the maximum size of an object. @@ -214,6 +205,12 @@ class hoardHeap { static void initNumProcs(void); protected: + // The maximum number of thread heaps we allow. (NOT the maximum + // number of threads -- Hoard imposes no such limit.) This must be + // a power of two! NB: This number is twice the maximum number of + // PROCESSORS supported by Hoard. + static int fMaxThreadHeaps; + // number of CPUs, cached static int _numProcessors; static int _numProcessorsMask; diff --git a/src/system/libroot/posix/malloc/processheap.cpp b/src/system/libroot/posix/malloc/processheap.cpp index 989e145a93..129cf4c3a0 100644 --- a/src/system/libroot/posix/malloc/processheap.cpp +++ b/src/system/libroot/posix/malloc/processheap.cpp @@ -35,25 +35,44 @@ using namespace BPrivate; -processHeap::processHeap(void) - : _buffer(NULL), _bufferCount(0) +processHeap::processHeap() + : + theap((HEAPTYPE*)hoardSbrk(sizeof(HEAPTYPE) * fMaxThreadHeaps)), #if HEAP_FRAG_STATS - , _currentAllocated(0), + _currentAllocated(0), _currentRequested(0), - _maxAllocated(0), _inUseAtMaxAllocated(0), _maxRequested(0) + _maxAllocated(0), + _inUseAtMaxAllocated(0), + _maxRequested(0), #endif +#if HEAP_LOG + _log((Log*) + hoardSbrk(sizeof(Log) * (fMaxThreadHeaps + 1))), +#endif + _buffer(NULL), + _bufferCount(0) { + if (theap == NULL) + return; + new(theap) HEAPTYPE[fMaxThreadHeaps]; + +#if HEAP_LOG + if (_log == NULL) + return; + new(_log) Log[fMaxThreadHeaps + 1]; +#endif + int i; // The process heap is heap 0. setIndex(0); - for (i = 0; i < MAX_HEAPS; i++) { + for (i = 0; i < fMaxThreadHeaps; i++) { // Set every thread's process heap to this one. theap[i].setpHeap(this); // Set every thread heap's index. theap[i].setIndex(i + 1); } #if HEAP_LOG - for (i = 0; i < MAX_HEAPS + 1; i++) { + for (i = 0; i < fMaxThreadHeaps + 1; i++) { char fname[255]; sprintf(fname, "log%d", i); unlink(fname); @@ -74,7 +93,7 @@ processHeap::stats(void) #if HEAP_STATS int umax = 0; int amax = 0; - for (int j = 0; j < MAX_HEAPS; j++) { + for (int j = 0; j < fMaxThreadHeaps; j++) { for (int i = 0; i < SIZE_CLASSES; i++) { amax += theap[j].maxAllocated(i) * sizeFromClass(i); umax += theap[j].maxInUse(i) * sizeFromClass(i); @@ -98,7 +117,7 @@ processHeap::stats(void) #if HEAP_LOG printf("closing logs.\n"); fflush(stdout); - for (int i = 0; i < MAX_HEAPS + 1; i++) { + for (int i = 0; i < fMaxThreadHeaps + 1; i++) { _log[i].close(); } #endif diff --git a/src/system/libroot/posix/malloc/processheap.h b/src/system/libroot/posix/malloc/processheap.h index 5d9125e674..f2222897f2 100644 --- a/src/system/libroot/posix/malloc/processheap.h +++ b/src/system/libroot/posix/malloc/processheap.h @@ -51,7 +51,7 @@ class processHeap : public hoardHeap { // we parcel out. enum { REFILL_NUMBER_OF_SUPERBLOCKS = 16 }; - processHeap(void); + processHeap(); ~processHeap(void) { #if HEAP_STATS @@ -133,7 +133,7 @@ class processHeap : public hoardHeap { const processHeap & operator=(const processHeap &); // The per-thread heaps. - HEAPTYPE theap[MAX_HEAPS]; + HEAPTYPE* theap; #if HEAP_FRAG_STATS // Statistics required to compute fragmentation. We cannot @@ -152,7 +152,7 @@ class processHeap : public hoardHeap { #endif #if HEAP_LOG - Log < MemoryRequest > _log[MAX_HEAPS + 1]; + Log < MemoryRequest >* _log; #endif // A lock for the superblock buffer. @@ -166,8 +166,9 @@ class processHeap : public hoardHeap { HEAPTYPE & processHeap::getHeap(int i) { + assert(theap != NULL); assert(i >= 0); - assert(i < MAX_HEAPS); + assert(i < fMaxThreadHeaps); return theap[i]; } @@ -176,8 +177,9 @@ processHeap::getHeap(int i) Log & processHeap::getLog(int i) { + assert(_log != NULL); assert(i >= 0); - assert(i < MAX_HEAPS + 1); + assert(i < fMaxThreadHeaps + 1); return _log[i]; } #endif @@ -192,7 +194,7 @@ processHeap::getHeapIndex(void) // In fact, for efficiency, we just round up to the highest power of two, // times two. int tid = find_thread(NULL) & _numProcessorsMask; - assert(tid < MAX_HEAPS); + assert(tid < fMaxThreadHeaps); return tid; } diff --git a/src/system/libroot/posix/malloc/wrapper.cpp b/src/system/libroot/posix/malloc/wrapper.cpp index 2af067fa5b..5b5e06680e 100644 --- a/src/system/libroot/posix/malloc/wrapper.cpp +++ b/src/system/libroot/posix/malloc/wrapper.cpp @@ -46,7 +46,7 @@ using namespace BPrivate; #if HEAP_LEAK_CHECK static block* sUsedList = NULL; -static hoardLockType sUsedLock = 0; +static hoardLockType sUsedLock = MUTEX_INITIALIZER(""); /*! @@ -250,7 +250,7 @@ inline static processHeap * getAllocator(void) { static char *buffer = (char *)hoardSbrk(sizeof(processHeap)); - static processHeap *theAllocator = new (buffer) processHeap; + static processHeap *theAllocator = new (buffer) processHeap(); return theAllocator; } diff --git a/src/system/libroot/posix/pthread/pthread_key.cpp b/src/system/libroot/posix/pthread/pthread_key.cpp index 956c98018b..431a4d4481 100644 --- a/src/system/libroot/posix/pthread/pthread_key.cpp +++ b/src/system/libroot/posix/pthread/pthread_key.cpp @@ -106,7 +106,7 @@ pthread_key_delete(pthread_key_t key) if (key < 0 || key >= PTHREAD_KEYS_MAX) return EINVAL; - int32 sequence = atomic_set(&sKeyTable[key].sequence, + int32 sequence = atomic_get_and_set(&sKeyTable[key].sequence, PTHREAD_UNUSED_SEQUENCE); if (sequence == PTHREAD_UNUSED_SEQUENCE) return EINVAL; diff --git a/src/system/libroot/posix/pthread/pthread_once.cpp b/src/system/libroot/posix/pthread/pthread_once.cpp index e83627a571..7ef275452b 100644 --- a/src/system/libroot/posix/pthread/pthread_once.cpp +++ b/src/system/libroot/posix/pthread/pthread_once.cpp @@ -26,7 +26,8 @@ init_function_canceled(void* data) pthread_once_t* onceControl = (pthread_once_t*)data; // reset the control state to uninitialized - int32 value = atomic_set((vint32*)&onceControl->state, STATE_UNINITIALIZED); + int32 value = atomic_get_and_set((int32*)&onceControl->state, + STATE_UNINITIALIZED); // If someone has set a semaphore, delete it. if (value >= 0) @@ -54,7 +55,7 @@ pthread_once(pthread_once_t* onceControl, void (*initRoutine)(void)) // initRoutine. All following threads will return right away. while (true) { - int32 value = atomic_test_and_set((vint32*)&onceControl->state, + int32 value = atomic_test_and_set((int32*)&onceControl->state, STATE_INITIALIZING, STATE_UNINITIALIZED); if (value == STATE_INITIALIZED) @@ -66,7 +67,8 @@ pthread_once(pthread_once_t* onceControl, void (*initRoutine)(void)) initRoutine(); pthread_cleanup_pop(false); - value = atomic_set((vint32*)&onceControl->state, STATE_INITIALIZED); + value = atomic_get_and_set((int32*)&onceControl->state, + STATE_INITIALIZED); // If someone else is waiting, we need to delete the semaphore. if (value >= 0) @@ -81,7 +83,7 @@ pthread_once(pthread_once_t* onceControl, void (*initRoutine)(void)) sem_id semaphore = create_sem(0, "pthread once"); if (semaphore >= 0) { // successfully created -- set it - value = atomic_test_and_set((vint32*)&onceControl->state, + value = atomic_test_and_set((int32*)&onceControl->state, semaphore, STATE_INITIALIZING); if (value == STATE_INITIALIZING) value = semaphore; @@ -91,7 +93,7 @@ pthread_once(pthread_once_t* onceControl, void (*initRoutine)(void)) // Failed to create the semaphore. Can only happen when the // system runs out of semaphores, but we can still handle the // situation gracefully by spinning. - value = atomic_test_and_set((vint32*)&onceControl->state, + value = atomic_test_and_set((int32*)&onceControl->state, STATE_SPINNING, STATE_INITIALIZING); if (value == STATE_INITIALIZING) value = STATE_SPINNING; @@ -105,7 +107,7 @@ pthread_once(pthread_once_t* onceControl, void (*initRoutine)(void)) return 0; } else if (value == STATE_SPINNING) { // out of semaphores -- spin - while (atomic_get((vint32*)&onceControl->state) == STATE_SPINNING); + while (atomic_get((int32*)&onceControl->state) == STATE_SPINNING); } } } diff --git a/src/system/libroot/posix/scheduler.cpp b/src/system/libroot/posix/scheduler.cpp index f56543d023..a77f82a3ed 100644 --- a/src/system/libroot/posix/scheduler.cpp +++ b/src/system/libroot/posix/scheduler.cpp @@ -26,9 +26,9 @@ int sched_get_priority_min(int policy) { switch (policy) { - case SCHED_FIFO: case SCHED_RR: - case SCHED_SPORADIC: + return B_FIRST_REAL_TIME_PRIORITY; + case SCHED_OTHER: return B_LOW_PRIORITY; @@ -43,9 +43,9 @@ int sched_get_priority_max(int policy) { switch (policy) { - case SCHED_FIFO: case SCHED_RR: - case SCHED_SPORADIC: + return B_REAL_TIME_PRIORITY; + case SCHED_OTHER: return B_URGENT_DISPLAY_PRIORITY; diff --git a/src/system/libroot/posix/sys/uname.c b/src/system/libroot/posix/sys/uname.c index 120a95157d..18ea62a07a 100644 --- a/src/system/libroot/posix/sys/uname.c +++ b/src/system/libroot/posix/sys/uname.c @@ -20,9 +20,12 @@ int uname(struct utsname *info) { + cpu_topology_node_info root; system_info systemInfo; const char *platform; const char *haikuRevision; + uint32_t count = 1; + status_t error; if (!info) { __set_errno(B_BAD_VALUE); @@ -44,24 +47,20 @@ uname(struct utsname *info) snprintf(info->release, sizeof(info->release), "%" B_PRId64, systemInfo.kernel_version); - // TODO: make this better - switch (systemInfo.platform_type) { - case B_BEBOX_PLATFORM: - platform = "BeBox"; - break; - case B_MAC_PLATFORM: - platform = "BeMac"; - break; - case B_AT_CLONE_PLATFORM: - platform = "BePC"; - break; - case B_64_BIT_PC_PLATFORM: - platform = "x86_64"; - break; - default: - platform = "unknown"; - break; + error = get_cpu_topology_info(&root, &count); + if (error != B_OK || count < 1) + platform = "unknown"; + else { + switch (root.data.root.platform) { + case B_CPU_x86: + platform = "BePC"; + break; + case B_CPU_x86_64: + platform = "x86_64"; + break; + } } + strlcpy(info->machine, platform, sizeof(info->machine)); if (gethostname(info->nodename, sizeof(info->nodename)) != 0) diff --git a/src/system/libroot/posix/unistd/conf.cpp b/src/system/libroot/posix/unistd/conf.cpp index 50f09b8c5e..323a6b9099 100644 --- a/src/system/libroot/posix/unistd/conf.cpp +++ b/src/system/libroot/posix/unistd/conf.cpp @@ -99,8 +99,6 @@ __sysconf(int name) return _POSIX_THREADS; case _SC_IOV_MAX: return IOV_MAX; - case _SC_NPROCESSORS_MAX: - return B_MAX_CPU_COUNT; case _SC_NPROCESSORS_CONF: { system_info info; @@ -126,8 +124,6 @@ __sysconf(int name) count++; return count; } - case _SC_CPUID_MAX: - return B_MAX_CPU_COUNT - 1; case _SC_ATEXIT_MAX: return ATEXIT_MAX; case _SC_PASS_MAX: diff --git a/src/system/runtime_loader/runtime_loader.cpp b/src/system/runtime_loader/runtime_loader.cpp index 5467b2a36f..16bb18fde2 100644 --- a/src/system/runtime_loader/runtime_loader.cpp +++ b/src/system/runtime_loader/runtime_loader.cpp @@ -31,6 +31,8 @@ struct user_space_program_args *gProgramArgs; void *__gCommPageAddress; void *__dso_handle; +int32 __gCPUCount = 1; + static const char * search_path_for_type(image_type type) diff --git a/src/tools/fs_shell/atomic.cpp b/src/tools/fs_shell/atomic.cpp index 1899a9fada..ebfcdc56d4 100644 --- a/src/tools/fs_shell/atomic.cpp +++ b/src/tools/fs_shell/atomic.cpp @@ -10,86 +10,100 @@ #include "fssh_atomic.h" -int32_t -fssh_atomic_set(vint32_t *value, int32_t newValue) +void +fssh_atomic_set(int32_t* value, int32_t newValue) { - return atomic_set((vint32*)value, newValue); + atomic_set((int32*)value, newValue); } int32_t -fssh_atomic_test_and_set(vint32_t *value, int32_t newValue, int32_t testAgainst) +fssh_atomic_get_and_set(int32_t* value, int32_t newValue) { - return atomic_test_and_set((vint32*)value, newValue, testAgainst); + return atomic_get_and_set((int32*)value, newValue); } int32_t -fssh_atomic_add(vint32_t *value, int32_t addValue) +fssh_atomic_test_and_set(int32_t *value, int32_t newValue, int32_t testAgainst) { - return atomic_add((vint32*)value, addValue); + return atomic_test_and_set((int32*)value, newValue, testAgainst); } int32_t -fssh_atomic_and(vint32_t *value, int32_t andValue) +fssh_atomic_add(int32_t *value, int32_t addValue) { - return atomic_and((vint32*)value, andValue); + return atomic_add((int32*)value, addValue); } int32_t -fssh_atomic_or(vint32_t *value, int32_t orValue) +fssh_atomic_and(int32_t *value, int32_t andValue) { - return atomic_or((vint32*)value, orValue); + return atomic_and((int32*)value, andValue); } int32_t -fssh_atomic_get(vint32_t *value) +fssh_atomic_or(int32_t *value, int32_t orValue) { - return atomic_get((vint32*)value); + return atomic_or((int32*)value, orValue); +} + + +int32_t +fssh_atomic_get(int32_t *value) +{ + return atomic_get((int32*)value); +} + + +void +fssh_atomic_set64(int64_t *value, int64_t newValue) +{ + atomic_set64((int64*)value, newValue); } int64_t -fssh_atomic_set64(vint64_t *value, int64_t newValue) +fssh_atomic_get_and_set64(int64_t* value, int64_t newValue) { - return atomic_set64((vint64*)value, newValue); + return atomic_get_and_set64((int64*)value, newValue); } int64_t -fssh_atomic_test_and_set64(vint64_t *value, int64_t newValue, int64_t testAgainst) +fssh_atomic_test_and_set64(int64_t *value, int64_t newValue, int64_t testAgainst) { - return atomic_test_and_set64((vint64 *)value, newValue, testAgainst); + return atomic_test_and_set64((int64 *)value, newValue, testAgainst); } int64_t -fssh_atomic_add64(vint64_t *value, int64_t addValue) +fssh_atomic_add64(int64_t *value, int64_t addValue) { - return atomic_add64((vint64*)value, addValue); + return atomic_add64((int64*)value, addValue); } int64_t -fssh_atomic_and64(vint64_t *value, int64_t andValue) +fssh_atomic_and64(int64_t *value, int64_t andValue) { - return atomic_and64((vint64*)value, andValue); + return atomic_and64((int64*)value, andValue); } int64_t -fssh_atomic_or64(vint64_t *value, int64_t orValue) +fssh_atomic_or64(int64_t *value, int64_t orValue) { - return atomic_or64((vint64*)value, orValue); + return atomic_or64((int64*)value, orValue); } int64_t -fssh_atomic_get64(vint64_t *value) +fssh_atomic_get64(int64_t *value) { - return atomic_get64((vint64*)value); + return atomic_get64((int64*)value); } diff --git a/src/tools/fs_shell/vfs.cpp b/src/tools/fs_shell/vfs.cpp index bd7e1cd1af..55a37b5dd4 100644 --- a/src/tools/fs_shell/vfs.cpp +++ b/src/tools/fs_shell/vfs.cpp @@ -3608,10 +3608,10 @@ common_lock_node(int fd, bool kernel) // We need to set the locking atomically - someone // else might set one at the same time #ifdef __x86_64__ - if (fssh_atomic_test_and_set64((vint64_t *)&vnode->mandatory_locked_by, + if (fssh_atomic_test_and_set64((int64_t *)&vnode->mandatory_locked_by, (fssh_addr_t)descriptor, 0) != 0) #else - if (fssh_atomic_test_and_set((vint32_t *)&vnode->mandatory_locked_by, + if (fssh_atomic_test_and_set((int32_t *)&vnode->mandatory_locked_by, (fssh_addr_t)descriptor, 0) != 0) #endif status = FSSH_B_BUSY; @@ -3636,10 +3636,10 @@ common_unlock_node(int fd, bool kernel) // We need to set the locking atomically - someone // else might set one at the same time #ifdef __x86_64__ - if (fssh_atomic_test_and_set64((vint64_t *)&vnode->mandatory_locked_by, + if (fssh_atomic_test_and_set64((int64_t *)&vnode->mandatory_locked_by, 0, (fssh_addr_t)descriptor) != (int64_t)descriptor) #else - if (fssh_atomic_test_and_set((vint32_t *)&vnode->mandatory_locked_by, + if (fssh_atomic_test_and_set((int32_t *)&vnode->mandatory_locked_by, 0, (fssh_addr_t)descriptor) != (int32_t)descriptor) #endif status = FSSH_B_BAD_VALUE;