Seluruh kebenaran tentang RTOS. Artikel # 9. Penjadwal: implementasi


Prinsip-prinsip dasar pekerjaan para perencana RTOS dipertimbangkan dalam artikel “Tugas dan Perencanaan”. Pada artikel ini, kita akan melihat fitur-fitur yang ditawarkan Nucleus RTOS, serta yang disediakan Nucleus SE secara lebih rinci.


Artikel sebelumnya dalam seri:
Artikel # 8. Nucleus SE: Desain dan Penyebaran Internal
Artikel # 7. Nucleus SE: Pendahuluan
Artikel # 6. Layanan RTOS lainnya
Artikel # 5. Interaksi tugas dan sinkronisasi
Artikel # 4. Tugas, pengalihan konteks, dan interupsi
Artikel # 3. Tugas dan Perencanaan
Artikel # 2. RTOS: Struktur dan mode waktu-nyata
Artikel # 1. RTOS: pengantar.


Perencanaan di RTOS Inti


Karena Nucleus RTOS adalah RTOS komersial lengkap dan mapan, kita dapat dengan aman mengasumsikan bahwa penjadwal dikembangkan sesuai dengan persyaratan produk tersebut. Sistem operasi yang kompleks dan fleksibel ini memberikan pengembang berbagai kemampuan untuk menyelesaikan hampir semua tugas pemrograman waktu nyata yang mungkin dilakukan.


Penjadwal dapat mendukung jumlah tugas yang tidak terbatas (hanya dibatasi oleh sumber daya yang tersedia) dan bekerja dengan manajemen prioritas. Tugas dapat diberikan prioritas dari 0 hingga 255, di mana 0 adalah prioritas tertinggi, dan 255 adalah yang terendah. Suatu tugas memiliki prioritas yang dinamis, yaitu dapat diubah pada saat dijalankan baik oleh tugas itu sendiri atau oleh yang lain. Beberapa tugas dapat diberikan tingkat prioritas yang sama. Dalam kasus yang ekstrem, semua tugas dapat diberi prioritas yang sama, yang memungkinkan untuk menerapkan kebijakan perencanaan pada prinsip Round Robin dan Time-Slice.
Jika ada beberapa tugas dengan prioritas yang sama, mereka akan dijadwalkan menggunakan algoritma Round Robin sesuai urutan persiapannya. Tugas harus menghentikan sementara atau mentransfer kontrol sehingga tugas berikutnya dimulai. Tugas juga dapat diberikan interval waktu yang memberikan pemisahan waktu prosesor yang lebih terkontrol.


Perencanaan tugas adalah 100% deterministik, yang diharapkan dari inti yang sama. Tugas juga dapat dibuat dan dihancurkan secara dinamis, yang, berkat penjadwal, terjadi tanpa disadari oleh pengguna.


Perencanaan di Nucleus SE


Saya mengembangkan semua aspek Nucleus SE sehingga mereka umumnya kompatibel dengan Nucleus RTOS, tetapi juga lebih sederhana dan lebih efisien dalam hal memori. Penjadwal tidak terkecuali. Ini menyediakan banyak fitur dari Penjadwal RTOS Nucleus, tetapi agak terbatas. Fleksibilitas dicapai melalui konfigurasi selama perakitan.
Aplikasi Nucleus SE dapat memiliki maksimum 16 tugas (dan setidaknya satu). Meskipun secara teoritis jumlah ini dapat ditingkatkan, efisiensi algoritma akan berisiko; sejumlah struktur data bergantung pada penyimpanan nomor indeks tugas (dari 0 hingga 15) dalam nibble (empat bit), dan mereka perlu diproses bersama dengan kode yang sesuai.


Untuk mencapai keseimbangan antara fleksibilitas dan kesederhanaan (dan ukuran), alih-alih memiliki satu penjadwal dengan beberapa kemampuan, Nucleus SE menawarkan satu dari empat jenis penjadwal yang dapat dipilih: Jalankan ke Komponen (RTC), Round Robin (RR), Time-Slice ( TS) dan Prioritas. Penjadwal dipilih secara statis pada saat perakitan. Rincian tentang setiap jenis penjadwal dijelaskan di bawah ini di bagian "Jenis Penjadwal".


Seperti aspek Nucleus SE lainnya, tugas adalah objek statis. Mereka ditentukan selama konfigurasi, dan prioritas mereka (indeks) tidak dapat diubah.


Perencana Inti SE


Seperti yang dinyatakan di atas, Nucleus SE menawarkan satu dari empat jenis penjadwal untuk dipilih. Seperti kebanyakan aspek dari konfigurasi Nucleus SE, pilihan ini ditentukan dengan menulis ke nuse_config.h, parameter NUSE_SCHEDULER_TYPE harus diatur sesuai, seperti yang ditunjukkan dalam fragmen ini dari file konfigurasi:



Terlepas dari penjadwal mana yang dipilih, kode startupnya dipanggil segera setelah sistem diinisialisasi. Informasi lengkap tentang inisialisasi Nucleus SE akan disajikan pada artikel berikutnya.


Jalankan ke Penjadwal Penyelesaian


Penjadwal RTC adalah solusi termudah dan paling cocok jika memenuhi persyaratan aplikasi. Setiap tugas harus menyelesaikan pekerjaannya sebelum melakukan fungsi kembali dan memungkinkan penjadwal untuk menyelesaikan tugas berikutnya.


Tidak perlu ada tumpukan terpisah untuk setiap tugas. Semua kode ditulis dalam C, bahasa assembly tidak diperlukan. Di bawah ini adalah seluruh kode penjadwal RTC.



Kode hanyalah loop tanpa akhir yang bergantian memanggil setiap tugas. Array NUSE_Task_Start_Address [] berisi pointer ke fungsi eksternal dari setiap tugas. Makro PF0 adalah konversi sederhana dari pointer kosong ke pointer ke fungsi kosong tanpa parameter. Ini dirancang untuk memastikan keterbacaan kode.
Kompilasi bersyarat digunakan untuk mengaktifkan dukungan untuk fungsi tambahan: NUSE_SUSPEND_ENABLE menentukan apakah tugas dapat ditangguhkan; NUSE_SCHEDULE_COUNT_SUPPORT menentukan apakah nilai penghitung diperlukan setiap kali tugas dijadwalkan. Informasi lebih lanjut tentang ini dapat ditemukan di artikel selanjutnya.


Penjadwal Round Robin


Jika sedikit lebih banyak fleksibilitas diperlukan daripada yang disediakan oleh penjadwal RTC, penjadwal RR cocok. Ini memungkinkan tugas untuk mentransfer kontrol atau jeda, dan kemudian melanjutkan dari titik yang sama. Overhead tambahan, selain kompleksitas kode dan non-portabilitas, adalah bahwa setiap tugas memerlukan tumpukannya sendiri.
Kode penjadwal terdiri dari dua bagian. Komponen peluncuran adalah sebagai berikut:



Jika dukungan untuk keadaan awal tugas diaktifkan (menggunakan parameter NUSE_INITIAL_TASK_STATE_SUPPOR T, lihat "Parameter" di artikel berikutnya), perencanaan dimulai dari tugas selesai yang pertama; jika tidak, tugas dengan indeks 0 digunakan. Konteks tugas ini kemudian dimuat menggunakan NUSE_Context_Load () . Untuk informasi lebih lanjut tentang menyimpan dan memulihkan konteks, lihat bagian "Menyimpan Konteks" di artikel berikutnya.


Bagian kedua dari penjadwal adalah komponen "perencanaan ulang":



Kode ini dipanggil ketika tugas membebaskan prosesor pusat atau berhenti.


Kode memilih tugas dengan indeks berikut untuk memulai dan menempatkan nilai di NUSE_Task_Next, dengan mempertimbangkan apakah penangguhan tugas diaktifkan atau tidak. Makro NUSE_CONTEXT_SWAP () kemudian digunakan untuk memohon pengalihan konteks menggunakan interupsi perangkat lunak. Untuk informasi lebih lanjut tentang menyimpan dan memulihkan konteks, lihat bagian "Menyimpan Konteks" di artikel berikutnya.


Penjadwal Prioritas


Penjadwal Prioritas di Nucleus SE, seperti opsi lainnya, dirancang untuk menyediakan fungsionalitas yang diperlukan, sementara cukup sederhana. Akibatnya, setiap tugas memiliki prioritas yang unik, tidak mungkin memiliki beberapa tugas dengan satu tingkat prioritas. Prioritas ditentukan oleh indeks tugas, di mana 0 adalah tingkat prioritas tertinggi. Indeks tugas ditentukan oleh lokasinya di larik NUSE_Task_Start_Address []. Artikel selanjutnya akan memberikan informasi lebih rinci tentang pengaturan tugas.


Seperti penjadwal RR dan TS, penjadwal Prioritas memiliki dua komponen. Komponen startup dari penjadwal Prioritas sama dengan penjadwal RR dan TS, seperti yang diilustrasikan di atas. Komponen penjadwalan ulang sedikit berbeda:



Tidak ada kode kondisional yang dapat menonaktifkan penangguhan tugas, karena fitur ini wajib untuk penjadwal prioritas; alternatif apa pun tidak masuk akal. Fungsi NUSE_Reschedule () menerima parameter yang "memberi tahu" tugas mana yang dapat dijadwalkan berikutnya - new_task. Nilai ini ditetapkan ketika penjadwalan ulang dipanggil karena tugas lain dipanggil. Indeks tugas ini diteruskan sebagai parameter. Penjadwal kemudian dapat menentukan apakah akan melakukan pengalihan konteks dengan membandingkan nilai new_task dengan indeks tugas saat ini (NUSE_Task_Active) . Jika penjadwalan ulang adalah hasil dari jeda tugas, parameter akan ditetapkan ke NUSE_NO_TASK , dan penjadwal akan mencari tugas dengan prioritas tertinggi.


Status tugas


Sebagai aturan, semua sistem operasi memiliki konsep menemukan tugas dalam "keadaan" tertentu. Detailnya bervariasi tergantung pada RTOS. Pada artikel ini, kita akan melihat bagaimana Nucleus RTOS dan Nucleus SE menggunakan status tugas.


Status Tugas RTOS Inti


Nucleus RTOS mendukung 5 status tugas.


  • Eksekusi: Tugas saat ini mengelola prosesor. Jelas, hanya satu tugas yang dapat menempati keadaan ini.
  • Kesiapan: tugas yang siap untuk dieksekusi (atau untuk melanjutkan eksekusi) sebelum perencana memutuskan untuk meluncurkannya. Biasanya, tugas memiliki prioritas lebih rendah daripada yang sedang dilakukan.
  • Penangguhan: tugas "tidur". Itu tidak diperhitungkan selama perencanaan sampai bangun, dan pada saat itu akan "siap" dan dapat terus dieksekusi nanti. Biasanya tugas dalam keadaan "tidur" karena menunggu sesuatu: ketika sumber daya tersedia, ketika periode waktu yang ditentukan berakhir, atau ketika tugas lain membangunkannya.
  • Batalkan: tugas itu "terbunuh." Itu tidak diperhitungkan selama perencanaan sampai diatur ulang, setelah itu tugas akan "siap" atau "ditangguhkan".
  • Berakhir: tugas diselesaikan dan keluar dari fungsi eksternalnya dengan hanya meninggalkan unit eksternal atau dengan menjalankan pernyataan pengembalian. Itu tidak diperhitungkan selama perencanaan sampai diatur ulang, setelah itu tugas akan "siap" atau "ditangguhkan".
Karena Nucleus RTOS mendukung penciptaan dan penghancuran objek secara dinamis, termasuk tugas, tugas tersebut juga dapat dipertimbangkan dalam keadaan "jauh". Namun, karena segera setelah tugas dihapus, semua sumber daya sistemnya tidak ada lagi dan tugas itu sendiri tidak ada lagi, ia tidak dapat memiliki status. Kode tugas mungkin tersedia, tetapi objek tugas harus dibuat kembali.

Status tugas dalam Nucleus SE


Model status tugas di Nucleus SE sedikit lebih sederhana. Biasanya hanya ada 3 negara: Eksekusi, Ketersediaan, dan Jeda. Status setiap tugas disimpan di NUSE_Task_Status [] , yang memiliki nilai seperti NUSE_READY , meskipun tidak pernah memiliki nilai yang mencerminkan status Eksekusi. Jika penangguhan tugas tidak diaktifkan (lihat "Opsi" di artikel berikutnya), hanya dua status tugas yang dimungkinkan, dan larik ini tidak ada.

Ada beberapa jenis tugas jeda. Jika tugas secara eksplisit ditangguhkan dengan sendirinya atau oleh tugas lain, ini disebut "penangguhan murni" dan diwakili oleh status NUSE_PURE_SUSPEND. Jika status "tidur" aktif dan tugas ditangguhkan untuk jangka waktu tertentu, statusnya sudah
NUSE_SLEEP_SUSPEND . Jika fungsi memblokir panggilan API diaktifkan (melalui NUSE_BLOCKING_ENABLE , lihat “Parameter” di artikel berikutnya), tugas dapat ditangguhkan hingga sumber daya tersedia. Setiap jenis objek memiliki status penangguhan tugasnya sendiri, misalnya, dalam bentuk NUSE_MAILBOX_SUSPEND. Dalam Nucleus SE, tugas dapat dikunci dalam partisi memori, grup acara, kotak surat, antrian, saluran, atau semafor.

Status utas


Saat membahas perilaku tugas, kata-kata "Status" dan "Status" biasanya digunakan dengan cukup bebas. Ada faktor tambahan, yang secara kondisional dapat disebut "keadaan aliran". Ini adalah variabel global NUSE_Thread_State, yang berisi indikasi sifat kode yang dieksekusi. Ini berlaku untuk perilaku banyak panggilan API. Nilai yang mungkin:

  • NUSE_TASK_CONTEXT - Panggilan API dibuat dari tugas.
  • NUSE_STARTUP_CONTEXT - panggilan API dilakukan dari kode startup; penjadwal belum dimulai.
  • NUSE_NISR_CONTEXT dan NUSE_MISR_CONTEXT - panggilan API dilakukan dari interrupt handler. Gangguan pada Nucleus SE akan dibahas pada artikel berikutnya.

Artikel selanjutnya akan merinci fitur penjadwal lanjutan di Nucleus SE, serta mempertahankan konteks.

Tentang Pengarang: Colin Walls telah bekerja di industri elektronik selama lebih dari tiga puluh tahun, mencurahkan sebagian besar waktunya untuk firmware. Dia sekarang adalah seorang insinyur firmware di Mentor Embedded (sebuah divisi dari Mentor Graphics). Colin Walls sering berbicara di konferensi dan seminar, penulis berbagai artikel teknis dan dua buku tentang firmware. Tinggal di Inggris. Blog Profesional Colin , email: colin_walls@mentor.com

Source: https://habr.com/ru/post/id422615/


All Articles