1 Linux System Programming in C Desember, 02 Tentang Penulis Abdul Yadi. Lulus dari Institut Keguruan dan Ilmu Pendidikan Padang tahun. Founder dan pr...
Tentang Penulis Abdul Yadi. Lulus dari Institut Keguruan dan Ilmu Pendidikan Padang tahun 1994. Founder dan programer di Datatrans Informatika. Aktif berinovasi dalam pemrograman backend server database PostgreSQL dan aplikasi web berbasis Google Web Toolkit dan Sencha GXT. Menerima anugerah Merit Winner dalam event Indonesia ICT Award 2012. Menerima Gold Award dalam event ASEAN ICT Awards 2013. Kontributor artikel teknologi server database PostgreSQL di Planet PostgreSQL (http://planet.postgresql.org/feeds.html).
Daftar Isi I Dasar Pemrograman C........................................................................................................... 1 1 Fungsi Main...................................................................................................................... 2 1.1 Definisi Fungsi Main.................................................................................................. 2 1.2 Input Fungsi Main..................................................................................................... 4 1.3 Return Fungsi Main................................................................................................... 5 2 Deklarasi Variabel dan Konstanta.....................................................................................7 2.1 Scope Global dan Lokal............................................................................................7 2.2 Lintas File.................................................................................................................. 8 2.3 Menempatkan Deklarasi dalam File Header...........................................................10 2.4 Deklarasi Static untuk Variabel dan Konstanta Privat.............................................10 3 Deklarasi dan Definisi Fungsi.......................................................................................... 12 3.1 Deklarasi dan Definisi Fungsi..................................................................................12 3.2 Library Fungsi......................................................................................................... 14 II Variabel dan Pointer............................................................................................................. 16 4 Layout Memori................................................................................................................ 17 4.1 Kernel Space dan User Space................................................................................17 4.2 Memeriksa User Space........................................................................................... 18 5 Variabel dan Konstanta................................................................................................... 21 5.1 Deklarasi Variabel................................................................................................... 21 5.2 Copy by Value......................................................................................................... 22 5.3 Magic Number dan DEFINE....................................................................................23 6 Pointer............................................................................................................................ 25 6.1 Alamat dan Nilai Pointer.......................................................................................... 25 6.2 Copy by Pointer...................................................................................................... 26 6.3 Array dan Pointer.................................................................................................... 27 6.4 Inisialisasi Array...................................................................................................... 28 6.5 String....................................................................................................................... 28 6.6 Inisialisasi String Bersumber dari Segmen Code....................................................30 6.7 Inisialisasi String Bersumber dari Segmen Stack....................................................31 6.8 Pointer Konstan...................................................................................................... 32 III Tipe Data............................................................................................................................ 34 7 Tipe Data Dasar.............................................................................................................. 35 8 Structure......................................................................................................................... 37 9 Byte Alignment................................................................................................................ 39 9.1 Structure dan Byte Alignment.................................................................................39 9.2 Mengatur Byte Alignment........................................................................................40 10 Union............................................................................................................................ 43 IV Alokasi Memori................................................................................................................... 45 11 Alokasi Memori di Stack................................................................................................ 46 11.1 Batas Alokasi Memori di Stack..............................................................................46 11.2 Scope dan Daur Hidup Variabel............................................................................47 11.3 Pengalamatan Mundur.......................................................................................... 48 12 Alokasi Memori di Heap................................................................................................ 49 V Function Argument Passing................................................................................................. 52 13 Argument Passing by Value.......................................................................................... 53 14 Argument Passing by Pointer........................................................................................55 15 Callback Function......................................................................................................... 57 VI Library................................................................................................................................. 59 16 Static Link Source Code................................................................................................ 60 16.1 Library................................................................................................................... 60 16.2 Main Module......................................................................................................... 61 17 Static Link Object Code................................................................................................ 63 17.1 Library................................................................................................................... 63
17.2 Main Module......................................................................................................... 64 18 Static Link Archive........................................................................................................ 66 18.1 Library................................................................................................................... 66 18.2 Main Module......................................................................................................... 68 19 Dynamic Link Shared Object......................................................................................... 70 19.1 Library................................................................................................................... 70 19.2 Main Module......................................................................................................... 70 VII Library I/O Standard untuk Merekam dan Membaca File..................................................74 20 Fungsi Library I/O Standard untuk Menyimpan VariableLength Record dalam Format Teks.............................................................................................................................. 75 20.1 Mendeklarasikan Struktur.....................................................................................75 20.2 Menyimpan Data................................................................................................... 76 21 Fungsi Library I/O Standard untuk Membaca VariableLength Record dalam Format Teks.............................................................................................................................. 80 22 Fungsi Library I/O Standard untuk Menyimpan FixedLength Record dalam Format Teks.............................................................................................................................. 82 22.1 Menyimpan Data................................................................................................... 82 23 Fungsi Library I/O Standard untuk Membaca FixedLength Record dalam Format Teks ...................................................................................................................................... 85 24 Fungsi Library I/O Standard untuk Menyimpan FixedLength Record dalam Format Binary............................................................................................................................ 87 24.1 Mendeklarasikan Struktur.....................................................................................87 24.2 Menyimpan Data................................................................................................... 87 25 Fungsi Library I/O Standard untuk Membaca FixedLength Record dalam Format Binary............................................................................................................................ 90 VIII Library I/O Low Level untuk Merekam dan Membaca File................................................92 26 Fungsi Library I/O Low Level untuk Menyimpan FixedLength Record dalam Format Binary............................................................................................................................ 93 27 Fungsi Library I/O Level untuk Membaca FixedLength Record dalam Format Binary. 96 28 Vector Write untuk Menyimpan FixedLength Record...................................................98 28.1 Satu Perusahaan dan Beberapa Departemen......................................................98 28.2 Vector Write.......................................................................................................... 99 29 Vector Read untuk Membaca FixedLength Record...................................................102 IX Komunikasi Via USB to parallel Port Converter................................................................104 30 Simulasi parallel Port Menggunakan USB to Parallel Port Converter.........................105 30.1 Menghubungkan Piranti Eksternal dengan DB25 Converter...............................105 30.2 Memeriksa Registrasi Driver...............................................................................106 30.3 Menemukan Path................................................................................................ 106 30.4 Source Code....................................................................................................... 107 X Komunikasi Via USB to Serial Port Converter...................................................................108 31 Mempersiapkan Inter Koneksi Serial Port dan Library................................................109 31.1 Inter Koneksi....................................................................................................... 109 31.2 Library................................................................................................................. 109 32 Mengirim dan Menerima Baris String..........................................................................112 32.1 Pengirim.............................................................................................................. 112 32.2 Penerima............................................................................................................. 113 32.3 Makefile............................................................................................................... 113 32.4 Eksekusi.............................................................................................................. 114 33 Menggunakan Vector Write untuk Mengirim Data.......................................................115 33.1 Pengirim.............................................................................................................. 115 33.2 Penerima............................................................................................................. 117 33.3 Makefile............................................................................................................... 118 33.4 Eksekusi.............................................................................................................. 118 XI Multithread........................................................................................................................ 119 34 Multi Thread dan Efisiensi........................................................................................... 120 34.1 Single Thread dan Masalah Efisiensi..................................................................120
34.2 Multi Thread........................................................................................................ 121 35 Race Condition........................................................................................................... 125 36 Mutex untuk Singkronisasi Akses Memori...................................................................127 37 Mutex untuk Singkronisasi Akses Piranti I/O...............................................................130 38 Mutex untuk Chat Via Serial Port................................................................................134 38.1 Library................................................................................................................. 134 38.2 Aplikasi................................................................................................................ 136 39 Loop yang Tidak Efisien.............................................................................................. 140 40 Condition Variable....................................................................................................... 143 41 Semaphore................................................................................................................. 146 42 Thread Pool................................................................................................................ 150 XII Multi Process................................................................................................................... 155 43 Fork............................................................................................................................. 156 44 Duplikat Memori.......................................................................................................... 158 45 Sub Program............................................................................................................... 160 45.1 Melaunch Sub Program.....................................................................................160 45.2 Menanti Sub Program......................................................................................... 161 46 Zombie Process.......................................................................................................... 163 46.1 Zombie................................................................................................................ 163 46.2 Menanggulangi Zombie Process.........................................................................164 47 Pipe............................................................................................................................. 167 48 Menghentikan Proses Background.............................................................................169 48.1 Mengirim Signal SIGTERM.................................................................................170 48.2 Mengirim Signal SIGKILL....................................................................................170 XIII Linux Daemon................................................................................................................. 172 49 Memprogram Daemon................................................................................................ 173 50 Merekam Aktivitas ke System Log..............................................................................176 51 Library untuk Launch Daemon dan Logging...............................................................179 52 Library untuk Memparse File Konfigurasi...................................................................182 53 Contoh Daemon.......................................................................................................... 186 53.1 Daemon.............................................................................................................. 186 53.2 Initscript............................................................................................................. 187 XIV Inter Process Communication........................................................................................190 54 FIFO............................................................................................................................ 191 54.1 Writer Close Lebih Awal......................................................................................191 54.2 Reader Close Lebih Awal....................................................................................192 54.3 Mengcreate FIFO............................................................................................... 192 54.4 Aplikasi untuk Mengirim Pesan...........................................................................192 54.5 Aplikasi untuk Membaca Pesan..........................................................................194 54.6 Skenario 1: Writer Close Lebih Awal...................................................................194 54.7 Skenario 2: Reader Close Lebih Awal.................................................................195 55 File Locking................................................................................................................. 196 55.1 Append................................................................................................................ 196 55.2 Write di Area File Tertentu..................................................................................197 55.3 Read di Area File Tertentu..................................................................................199 56 Message Queue.......................................................................................................... 202 56.1 Struktur untuk Queue Key...................................................................................202 56.2 Mengcreate Message Queue.............................................................................202 56.3 Mengirim Data..................................................................................................... 203 56.4 Memungut Data.................................................................................................. 207 57 Shared Memory Segment........................................................................................... 210 57.1 Struktur untuk Key.............................................................................................. 210 57.2 Struktur Data....................................................................................................... 210 57.3 Mengcreate dan Mendestroy Shared Memory Segment..................................211 57.4 Menyimpan Data................................................................................................. 212 57.5 Membaca Data.................................................................................................... 213
57.6 Mengujicoba Program......................................................................................... 215 58 Semaphore................................................................................................................. 217 58.1 Mengcreate dan Mendestroy Semaphore.........................................................217 58.2 Menyimpan Data dengan Proteksi Semaphore...................................................218 58.3 Mengujicoba Program......................................................................................... 220 59 Memory Mapped File.................................................................................................. 222 59.1 Struktur Data....................................................................................................... 222 59.2 Header untuk Operasi Data................................................................................223 59.3 Read................................................................................................................... 223 59.4 Append................................................................................................................ 224 59.5 Edit...................................................................................................................... 224 59.6 Main.................................................................................................................... 226 59.7 Makefile............................................................................................................... 227 59.8 Memeriksa Virtual Addess Space.......................................................................228 59.9 Menguji Interprocess Communication.................................................................229 60 Unix Domain Socket................................................................................................... 231 60.1 Header................................................................................................................ 232 60.2 Server................................................................................................................. 232 60.3 Client................................................................................................................... 234 60.4 Mengujicoba Socket............................................................................................ 235 61 TCP/IP Socket............................................................................................................ 237 61.1 Server................................................................................................................. 237 61.2 Client................................................................................................................... 240 61.3 Mengujicoba Socket............................................................................................ 241 XV PostgreSQL Stored Procedure Programming.................................................................243 62 Operasi Bilangan........................................................................................................ 244 62.1 Source Code....................................................................................................... 244 62.2 File SQL untuk Instalasi......................................................................................245 62.3 Makefile............................................................................................................... 245 62.4 Build dan Instalasi............................................................................................... 245 62.5 Mengujicoba Stored Procedure...........................................................................246 63 Operasi Text............................................................................................................... 247 63.1 Source Code....................................................................................................... 247 63.2 File SQL untuk Instalasi......................................................................................248 63.3 Makefile............................................................................................................... 248 63.4 Build dan Instalasi............................................................................................... 248 63.5 Operasi Text dalam PLPGSQL...........................................................................249 63.6 Mengujicoba Stored Procedure...........................................................................250 64 Mendrive Perangkat Keras........................................................................................252 64.1 Mengizinkan Access /dev/usb/lp0.......................................................................252 64.2 Source Code....................................................................................................... 252 64.3 File SQL untuk Instalasi......................................................................................253 64.4 Makefile............................................................................................................... 253 64.5 Build dan Instalasi............................................................................................... 254 64.6 Mengujicoba Stored Procedure...........................................................................255 65 Set Returning Function............................................................................................... 256 65.1 File Teks............................................................................................................. 256 65.2 Source Code....................................................................................................... 256 65.3 File SQL untuk Instalasi......................................................................................258 65.4 Makefile............................................................................................................... 259 65.5 Build dan Instalasi............................................................................................... 259 65.6 Mengujicoba Stored Procedure...........................................................................259 66 Server Programming Interface....................................................................................261 66.1 Tabel Work Order............................................................................................... 261 66.2 Source Code Insert Data.....................................................................................261 66.3 File SQL untuk Instalasi......................................................................................262
66.4 Makefile............................................................................................................... 263 66.5 Build dan Instalasi............................................................................................... 263 66.6 Mengujicoba Stored Procedure...........................................................................263 XVI Web Driven Linux Resources Programming...................................................................265 67 Menginvoke Fungsi Shared Library............................................................................266 67.1 Shared Library.................................................................................................... 266 67.2 Kode Javascript.................................................................................................. 267 67.3 HTML.................................................................................................................. 268 67.4 Deploy................................................................................................................. 269 67.5 Mengujicoba........................................................................................................ 269 68 Javascript Callback..................................................................................................... 271 68.1 Shared Library.................................................................................................... 271 68.2 Kode Javascript.................................................................................................. 272 68.3 HTML.................................................................................................................. 274 68.4 Mengujicoba........................................................................................................ 275 69 Mozilla Addon SDK..................................................................................................... 276 69.1 Instalasi Mozilla Addon SDK..............................................................................276 69.2 Mempersiapkan Addon......................................................................................276 69.3 Kerangka............................................................................................................. 277 69.4 Membuat HTML.................................................................................................. 278 69.5 Membuat Content Script.....................................................................................279 69.6 Membuat Addon Script......................................................................................279 69.7 Memdebug Paket Addon..................................................................................280 69.8 Membuild Paket Addon.....................................................................................280 69.9 Menginstalasi Addon.......................................................................................... 281 69.10 Mengujicoba...................................................................................................... 281
I Dasar Pemrograman C
1 Fungsi Main 2 Deklarasi Variabel dan Konstanta 3 Deklarasi dan Definisi Fungsi
Linux System Programming in C
1
Datatrans Informatika
1 Fungsi Main
Tujuan 1. Memahami definisi fungsi main. 2. Dapat mengkompilasi dan melink kode program menjadi executable file. 3. Dapat membuat Makefile. 4. Memahami input fungsi main. 5. Memehami return fungsi main.
1.1
Definisi Fungsi Main
Fungsi main adalah entrypoint suatu program. Eksekusi kode program dimulai dari fungsi tersebut. Buatlah source code berikut ini dan disimpan menjadi file job1.c. Listing 1. Definisi Fungsi Main — job1.c 1 2 3
int main(int argc, char* argv[]) { return 0; }
Kode pada baris 1 menunjukkan bahwa fungsi main memiliki dua input: bilangan bulat argc dan array string argv1. Fungsi tersebut memiliki sebuah output bertipe data integer (bilangan bulat). Kode pada baris 2 menunjukkan bahwa main menghasilkan output bernilai 02.
1.1.1
Kompilasi dan Linking
Untuk membuat sebuah executable file, source code harus dikompilasi menjadi kode objek yang dimengerti prosesor komputer. Linux menyediakan compiler bahasa C bernama gcc. %
gcc -c -Wall job1.c
Perintah tersebut menghasilkan sebuah kode objek job1.o. • Opsi c: gcc megkompilasi source code job1.c menjadi job1.o tanpa melakukan linking. • Opsi Wall (warn all): gcc menampilkan kejanggalan selama mengkompilasi source code. Selanjutnya kode objek tersebut dilink menjadi executable file: job1. %
gcc -o job1 job1.o
• Opsi o (output): output executable file adalah job1. Mari memeriksa filefile yang dihasilkan: % ls -lh total 20K -rwxrwxr-x 1 abdul abdul 8.3K Jul 29 09:39 job1 1 2
Dijelaskan dalam Input Fungsi Main, halaman 4. Dijelaskan dalam Return Fungsi Main, halaman 5.
Linux System Programming in C
2
Datatrans Informatika
-rw-rw-r-- 1 abdul abdul 48 Jul 28 23:16 job1.c -rw-rw-r-- 1 abdul abdul 1.3K Jul 29 09:39 job1.o
• job1.c: source code berisi kode program. • job1.o: kode objek hasil kompilasi job1.c. • job1: executable file hasil linking. Dua pekerjaan, kompilasi dan link, dapat disederhanakan menjadi sebaris perintah: %
gcc -o job1 -Wall job1.c
1.1.2
Makefile
Sebuah projek biasanya terdiri atas lebih dari satu source code. Guna menyederhanakan kompilasi dan linking menjadi executable file, kita dapat menggunakan Makefile. Ketik kode berikut ini dan simpan menjadi Makefile dalam satu direktori bersama source code job1.c. Listing 2. Makefile untuk job1 1 2 3 4 5 6
Perhatian Indent pada baris 4 dan 6 adalah TAB, bukan deretan spasi. Makefile terdiri atas 3 target: all, job1 dan job1.o. Untuk setiap target terdapat prerequisite yang terdapat di sebelah kanan simbol titik dua (:). Target all, job1 dan job1.o masing masing membutuhkan prerequisite job1, job1.o dan job1.c. Suatu target dieksekusi karena 2 syarat. Pertama, target tidak eksis. Kedua, target kadaluarsa dibandingkan prerequisite. Berbeda dengan job1 dan job1.o, target all bukanlah sebuah file. Oleh karena itu didaftarkan sebagai PHONY (baris 1). Selain prerequisite, suatu target dapat berisi resep berupa satu atau lebih perintah baris yang dikerjakan sesuai urutan tampilan. Setiap resep diawali dengan TAB. Baris 4 adalah resep untuk target job1. Demikian pula, baris 6 adalah resep untuk target job1.o. Kini, mari mencoba membuat executable file menggunakan Makefile. Pastikan berada dalam satu direktori dengan Makefile. Ketik baris pertama (baris selebihnya adalah output) berikut ini: % make gcc -c -Wall job1.c gcc -o job1 job1.o
Perintah make (tanpa argumen) mengeksekusi target pertama dalam Makefile, yaitu all. Jika berhasil maka percobaan kedua mengeksekusi make menghasilkan output sebagai berikut: % make make: Nothing to be done for `all'.
Hal ini membuktikan bahwa target dalam Makefile dieksekusi jika terjadi pemutakhiran prerequisite yang ditandai dengan perubahan timestamp.
Linux System Programming in C
3
Datatrans Informatika
Kita dapat mencoba menjalankan make untuk targettarget tertentu, misalnya: %
make job1
Atau: %
make job1.o
Kesimpulan 1. Fungsi main adalan entry point suatu program, 2. Fungsi main memiliki dua argumen input masingmasing bertipe bilangan bulat dan array string. 3. Fungsi main memiliki sebuah output bertipe bilangan bulat.
1.2
Input Fungsi Main
Sebagaimana dijelaskan sebelumnya, fungsi main memiliki dua input. Pertama, bilangan bulat argc berisi banyaknya argumen. Kedua, array string argv berisi daftar argumen. Untuk mengujinya mari mengetik source code berikut ini dan disimpan menjadi file job2.c. Listing 3. Memeriksa Argumen Fungsi Main — job2.c 1 2 3 4 5 6 7 8 9 10
#include <stdio.h> int main(int argc, char* argv[]) { int i; printf("banyaknya argumen %d\n", argc); for(i=0;i<argc;i++){ printf("argumen %d: %s\n", i, argv[i]); } return 0; }
Baris 1 menginclude stdio.h ke dalam source code. File tersebut berisi deklarasi untuk fungsi printf pada baris 5 dan 7. Dalam bahasa pemrograman C, fungsifungsi selain main harus dideklarasikan terlebih dahulu sebelum digunakan. Deklarasi terdiri atas 3 Item: 1) nama fungsi, 2) tipetipe data argumen, dan 3) tipe data return. Berikut ini adalah cuplikan isi file stdio.h yang mendeklarasikan fungsi printf: extern int printf (const char *__restrict __format, ...);
Fungsi ini mencetak string ke standard output (dalam hal ini layar console) sesuai format yang ditetapkan. Misalnya, jika argc bernilai 3 maka format dalam baris 5 (tanda \n berarti baris baru): "banyaknya argumen %d\n"
menghasilkan string: banyaknya argumen 3
Baris 6 dampai 8 adalah pengulangan menggunakan tipe for loop. Secara berurutan, program mencetak argumen ke layar console. Mari mengkompilasi dan melink source code menjadi executable file job2: %
gcc -o job2 -Wall job2.c
Percobaan pertama, eksekusi job2 sebagai berikut (hanya perlu mengetik baris pertama): % ./job2 banyaknya argumen 1 Linux System Programming in C
4
Datatrans Informatika
argumen 0: ./job2
Percobaan kedua: % ./job2 test banyaknya argumen 2 argumen 0: ./job2 argumen 1: test
Percobaan ketiga: % ./job2 test coder training banyaknya argumen 4 argumen 0: ./job2 argumen 1: test argumen 2: coder argumen 3: training
Kesimpulan 1. argc adalah banyaknya argumen suatu program termasuk nama program. 2. argv adalah array string berisi nama program dan argumenargumennya.
1.3
Return Fungsi Main
Fungsi main menghasilkan output bilangan bulat: 0 jika berhasil atau selain 0 sebagai kode error. Mari membuat dua source code, disimpan masingmasing sebagai job3a.c dan job3b.c. Listing 4. Fungsi Main Return 0 — job3a.c 1 2 3 4 5 6
Percobaan pertama, rantai proses job3a dan job3b dirangkai menggunakan logika AND (&&): % ./job3a && ./job3b job3a return 0 job3b return 1
Percobaan kedua, kebalikan dari percobaan pertama, job3b dan job3a menggunakan logika AND: % ./job3b && ./job3a job3b return 1
Kesimpulan Jika menggunakan penghubung AND, rantai proses berhenti jika output suatu proses bukan 0. Linux System Programming in C
5
Datatrans Informatika
Percobaan ketiga, rantai proses job3a dan job3b dirangkai menggunakan logika OR (||): % ./job3a || ./job3b job3a return 0
Percobaan keempat, kebalikan dari percobaan ketiga, job3b dan job3a menggunakan logika OR: % ./job3b || ./job3a job3b return 1 job3a return 0
Kesimpulan Jika menggunakan penghubung OR, rantai proses berhenti jika output suatu proses 0.
Linux System Programming in C
6
Datatrans Informatika
2 Deklarasi Variabel dan Konstanta
Tujuan 1. Dapat mendeklarasikan variabel dan konstanta dalam scope global dan lokal. 2. Dapat mengakses variabel dan konstanta secara lintas file source code. 3. Dapat mendeklarasikan variabel dan konstanta secara static. Secara umum suatu program terdiri atas perintah dan data. Data berada di memori, memiliki alamat dan nilai. Data yang nilainya dapat diubah disebut variabel. Sedangkan, data yang nilainya tidak dapat diubah disebut konstanta. Dalam pemrograman bahasa C, variabel dan konstanta harus dideklarasikan sebelum digunakan. Listing 6. Variabel belum Dideklarasikan — job4a.c 1 2 3 4 5
int main(int argc, char* argv[]) { a=10; return 0; }
Baris 3, variabel a diberi nilai 10. Karena belum dideklarasikan maka terdapat error ketika source code job4a.c dikompilasi. % gcc -o job4a -Wall job4a.c job4a.c: In function ‘main’: job4a.c:3:2: error: ‘a’ undeclared (first use in this function) a=10; ^ job4a.c:3:2: note: each undeclared identifier is reported only once for each function it appears in
2.1
Scope Global dan Lokal
Kita dapat mengatur deklarasi variabel dan konstanta dalam scope (ruang lingkup) global atau lokal. Listing 7. Deklarasi Variabel dalam Scope Global dan Lokal — job4b.c 1 2 3 4 5 6 7 8 9 10
int a; const int b=100; int main(int argc, char* argv[]) { int c; const int d=200; c=10; a=3*c+b; {
int e; const int f=300; e=40*f; c+=d+e+a+b; } c=2*d; return 0; } void f1() { int g; const int h=400; g=b+1; a=g*h; return; }
Baris 1 dan 2 masingmasing berisi deklarasi variabel a dan konstanta b secara global. Baik a maupun b dapat digunakan dalam fungsi main (baris 5 sampai 18), sub scope dalam fungsi main (baris 11 sampai 14) maupun f1 (baris 22 sampai 28). Baris 5 dan 6 masingmasing berisi deklarasi variabel c dan konstanta d secara lokal dalam fungsi main. Baik c maupun d hanya dapat digunakan dalam fungsi main (baris 5 sampai 18) dan sub scope di dalamnya ( baris 11 sampai 14). Baris 22 dan 23 masingmasing berisi deklarasi variabel g dan konstanta h secara lokal dalam fungsi f1. Baik g maupun h hanya dapat digunakan dalam fungsi f1 (baris 22 sampai 28) dan sub scope di dalamnya (contoh fungsi f1 tidak memiliki sub scope). Ada 3 istilah yang perlu dipahami berkaitan dengan deklarasi variabel: deklarasi, inisialisasi dan assignment. Listing 8. Deklarasi, Inisialisasi dan Assignment 1 2 3
int a; a=20; int b=30;
Baris 1, deklarasi variabel a. Baris 2, assignment (pemberian nilai) untuk variabel a. Baris 3, inisialisasi varabel b (deklarasi sekaligus assignment).
2.2
Lintas File
Variabel dan konstanta yang dideklarasikan dalam sebuah source code dapat diakses oleh fungsi dalam source code lainnya. Misalnya, kita ingin membuat sebuah executable file job4c yang terdiri atas 2 source code: job4c1.c berisi fungsi main dan job4c2.c berisi library fungsi dan variabelvariabel global. Listing 9. Library Fungsi dan Variabel Global — job4c2.c 1 2 3 4 5 6 7 8
#include <stdio.h> int a; const int b=20; int add() { a=10; printf("dalam fungsi add:\n");
Linux System Programming in C
8
Datatrans Informatika
9 10 11 12
printf("a alamat %p nilai %d\n", &a, a); printf("b alamat %p nilai %d\n", &b, b); return a+b; }
Baris 3 dan 4, variabel a dan konstanta b dideklarasikan dalam scope global. Baris 10, alamat dan nilai a diperiksa. Baris 11, hal yang sama untuk b. Baik variabel a, konstanta b maupun fungsi add ingin digunakan dalam fungsi main dalam source code job4c1.c. Listing 10. Menggunakan Variabel dan Konstanta Global — job4c1.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14
#include <stdio.h> extern int a; extern const int b; extern int add(); int main(int argc, char* argv[]) { int c=add(); printf("dalam fungsi main:\n"); printf("a alamat %p nilai %d\n", &a, a); printf("b alamat %p nilai %d\n", &b, b); printf("c alamat %p nilai %d\n", &c, c); return 0; }
Baris 3 sampai 5, mendeklarasikan variabel a, konstanta b dan fungsi add dengan kata kunci extern. Artinya, itemitem tersebut dideklarasikan di luar file source code job4c1.c. Kita dapat mengkompilasi dan melink job4c1.c dan job4c2.c menjadi executable file job4c sebagai berikut: %
gcc -o job4c -Wall job4c1.c job4c2.c
Atau membuat Makefile: Listing 11. Makefile untuk job4c 1 2 3 4 5 6 7 8
Lalu mengcreate job4c dengan mudah: % make gcc -c -Wall job4c1.c gcc -c -Wall job4c2.c gcc -o job4c job4c1.o job4c2.o
Mari memeriksa hasil eksekusi job4c: % ./job4c dalam fungsi add: a alamat 0x601040 nilai b alamat 0x400748 nilai dalam fungsi main: a alamat 0x601040 nilai b alamat 0x400748 nilai c alamat 0x7fffc95909ec Linux System Programming in C
10 20 10 20 nilai 30 9
Datatrans Informatika
Dengan cara memeriksa kesamaan alamat, terbukti bahwa variabel a dan konstanta b dalam fungsi main (source code job4c1.c) adalah variabel dan konstanta yang sama dalam fungsi add (source code job4c2.c).
2.3
Menempatkan Deklarasi dalam File Header
Kita telah berhasil membuat source code (job4c2.c) berisi deklarasi variabel, konstanta dan fungsi sebagai library yang diakses oleh source code lain (job4c1.c). Jika source code pengguna library bertambah banyak, kita harus memperbaiki cara mendeklarasikan itemitem eksternal (dengan kata kunci extern) agar tidak dilakukan berulangulang. Mari membuat file header bernama job4c2.h berisi deklarasi variabel, konstanta dan fungsi: Listing 12. File Header untuk Library — job4c2.h 1 2 3
extern int a; extern const int b; extern int add();
int main(int argc, char* argv[]) { int c=add(); printf("dalam fungsi main:\n"); printf("a alamat %p nilai %d\n", &a, a); printf("b alamat %p nilai %d\n", &b, b); printf("c alamat %p nilai %d\n", &c, c); return 0; }
Deklarasi baris 3 sampai 5 dibatalkan (boleh dihapus). Diganti dengan menginclude file header job4c2.h pada barus 6. Makefile harus diperbaiki. Kita perlu menambahkan job4c2.h sebagai prerequisite untuk target job4c1.o (baris 5) agar target tersebut dicreate setiap kali terjadi pemutakhiran job4c2.h: Listing 14. Makefile untuk job4c 1 2 3 4 5 6 7 8
Deklarasi Static untuk Variabel dan Konstanta Privat
Jika ingin membatasi akses variabel dan konstanta global secara privat hanya dalam file source code tempat itemitem tersebut dideklarasikan, kita dapat menggunakan deklarasi static. Linux System Programming in C
10
Datatrans Informatika
Mari mengubah deklarasi variabel dalam file source code job4c2.c. Listing 15. Deklarasi Static — job4c2.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14
#include <stdio.h> //int a; static int a; //const int b=20; static const int b=20; int add() { a=10; printf("dalam fungsi add:\n"); printf("a alamat %p nilai %d\n", &a, a); printf("b alamat %p nilai %d\n", &b, b); return a+b; }
Pada baris 3 dan 4, deklarasi variabel a diubah menjadi static. Baris 5 dan 6, deklarasi konstanta b diubah menjadi static. Selanjutnya, mari mencoba mengenerate executable file job4c menggunakan Makefile. % make gcc -c -Wall job4c2.c gcc -o job4c job4c1.o job4c2.o job4c1.o: In function `main': job4c1.c:(.text+0x28): undefined reference job4c1.c:(.text+0x2f): undefined reference job4c1.c:(.text+0x44): undefined reference job4c1.c:(.text+0x4b): undefined reference collect2: error: ld returned 1 exit status make: *** [job4c] Error 1
to to to to
`a' `a' `b' `b'
Perhatikan bahwa variabel a dan konstanta b yang dideklarasikan static dalam job4c2.c tidak dapat diakses oleh fungsi dalam file job4c1.c. Kesimpulan 1. Variabel dan konstanta harus dideklarasikan sebelum digunakan dalam source code. 2. Variabel dan konstanta dapat dideklarasikan dalam scope global atau lokal. 3. Variabel dan konstanta yang dideklarasikan dalam scope global dalam suatu source code dapat diakses oleh source code lain. 4. Variabel dan konstanta yang dideklarasikan static hanya dapat diakses dalam source code tempat itemitem tersebut dideklarasikan.
Linux System Programming in C
11
Datatrans Informatika
3 Deklarasi dan Definisi Fungsi
Tujuan 1. Dapat membuat deklarasi fungsi. 2. Dapat membuat definisi fungsi. 3. Dapat membuat library berisi fungsi untuk digunakan source code lain. Selain fungsi main, fungsifungsi dalam pemrograman bahasa C harus dideklarasikan dan didefinisikan. Deklarasi berisi penjelasan: 1) nama fungsi, 2) susunan dan tipe data argumen argumennya, 3) tipe data return (data yang diberikan oleh fungsi ketika alur program kembali ke pemanggil fungsi tersebut). Definisi berisi kode untuk menyelesaikan tugas fungsi.
3.1
Deklarasi dan Definisi Fungsi
Contoh, fungsi add bertugas menjumlahkan dua bilangan bulat. Kita memanggilnya dalam fungsi main. Listing 16. Fungsi tanpa Deklarasi — job5.c 1 2 3 4 5 6 7
int main(int argc, char* argv[]) { int a, b, c; a=10; b=20; c=add(a,b); return 0; }
Lalu membuat executable file job5:
% gcc -o job5 -Wall job5.c job5.c: In function ‘main’: job5.c:5:2: warning: implicit declaration of function ‘add’ [-Wimplicitfunction-declaration] c=add(a,b); ^ job5.c:2:12: warning: variable ‘c’ set but not used [-Wunused-but-setvariable] int a, b, c; ^ /tmp/cclmfmSl.o: In function `main': job5.c:(.text+0x2d): undefined reference to `add' collect2: error: ld returned 1 exit status
Perhatikan warning yang menyatakan bahwa fungsi add belum dideklarasikan (implicit declaration of function ‘add‘). Mari menambahkan deklarasi fungsi tersebut ke dalam source code. Listing 17. Mendeklarasikan Fungsi — job5.c 1
int add(int, int);
Linux System Programming in C
12
Datatrans Informatika
2 3 4 5 6 7 8 9
int main(int argc, char* argv[]) { int a, b, c; a=10; b=20; c=add(a,b); return 0; }
Membuat executable file:
% gcc -o job5 -Wall job5.c job5.c: In function ‘main’: job5.c:4:12: warning: variable ‘c’ set but not used [-Wunused-but-setvariable] int a, b, c; ^ /tmp/ccqIQo5E.o: In function `main': job5.c:(.text+0x28): undefined reference to `add' collect2: error: ld returned 1 exit status
Perhatikan warning yang menunjukkan bahwa variabel c tidak digunakan dalam fungsi main (variable ‘c’ set but not used). Untuk saat ini kita mengabaikannya karena memang variabel tersebut belum dimanfaatkan dalam fungsi main. Selain itu terdapat error yang menunjukkan bahwa fungsi add belum didefinisikan (undefined reference to `add'). Mari menambahkan definisi fungsi tersebut ke dalam source code. Listing 18. Mendefinisikan Fungsi — job5.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14
int add(int, int); int main(int argc, char* argv[]) { int a, b, c; a=10; b=20; c=add(a,b); return 0; } int add(int n1, int n2) { int n=n1+n2; return n; }
Membuat executable file:
% gcc -o job5 -Wall job5.c job5.c: In function ‘main’: job5.c:4:12: warning: variable ‘c’ set but not used [-Wunused-but-setvariable] int a, b, c; ^
Guna menghilangkan warning tersebut, mari menggunakan variabel c, misalnya dengan menampilkannya ke layar console menggunakan fungsi builtin printf. Kita tidak perlu membuat deklarasi dan definisinya. Fungsi tersebut telah dideklarasikan dalam file header stdio.h dan didefinisikan dalam file shared object libc.so. Shared object tersebut secara default dilink oleh gcc ke dalam executable file secara dinamik. Listing 19. Menggunakan Builtin Function — job5.c 1
#include <stdio.h>
Linux System Programming in C
13
Datatrans Informatika
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
int add(int, int); int main(int argc, char* argv[]) { int a, b, c; a=10; b=20; c=add(a,b); printf("%d+%d=%d\n", a, b, c); return 0; } int add(int n1, int n2) { int n=n1+n2; return n; }
Baris 1, menginclude stdio.h berisi deklarasi fungsi printf. Baris 10, menggunakan fungsi printf. Membuat executable file: %
gcc -o job5 -Wall job5.c
Mengeksekusi job5: % ./job5 10+20=30
3.2
Library Fungsi
Fungsi add dapat dipisahkan dari source code job5.c dan disusun menjadi library sehingga dapat digunakan juga untuk source code lain. Library terdiri atas: 1) deklarasi fungsi dalam file header joblib.h dan 2) definisi fungsi dalam file joblib.c. Listing 20. Deklarasi Library — joblib.h 1
extern int add(int, int);
Listing 21. Definisi Library — joblib.c 1 2 3 4
int add(int n1, int n2) { int n=n1+n2; return n; }
Perhatian Jika didefinisikan static (static int add(...)) maka fungsi add tidak dapat diakses source code lain. Mari membuat source code job5a.c untuk memanfaatkan library yang baru dibuat. Listing 22. Menggunakan Library — job5a.c 1 2 3 4 5 6 7 8 9 10
#include <stdio.h> #include "joblib.h" int main(int argc, char* argv[]) { int a, b, c; a=10; b=20; c=add(a,b); printf("%d+%d=%d\n", a, b, c); return 0;
Linux System Programming in C
14
Datatrans Informatika
11
}
Membuat executable file: %
gcc -o job5a -Wall job5a.c joblib.c
Atau menggunakan Makefile: Listing 23. Makefile untuk job5a 1 2 3 4 5 6 7 8
Membuat executable file menjadi lebih ringkas: % make gcc -c -Wall job5a.c gcc -c -Wall joblib.c gcc -o job5a job5a.o joblib.o
Mengeksekusi job5a: % ./job5a 10+20=30
Kesimpulan 1. Selain main, fungsifungsi harus dideklarasikan dan didefinisikan. 2. Library terdiri atas 2 bagian: 1) file header berisi deklarasi fungsi dan 2) file source code berisi definisi fungsi.
Linux System Programming in C
15
Datatrans Informatika
II Variabel dan Pointer
4 Layout Memori 5 Variabel dan Konstanta 6 Pointer
Linux System Programming in C
16
Datatrans Informatika
4 Layout Memori
Tujuan 1. Dapat memeriksa layout memori untuk menampung variabel dan konstanta. 2. Membuktikan perbedaan penempatan variabel dan konstanta dalam segmen memori.
4.1
Kernel Space dan User Space
Program yang dilaunching disebut proses. Untuk setiap proses, sistem operasi mengalokasikan memori untuk menampung kode dan data. Linux membagi 2 ruang memori: kernel space dan user space. Dalam sistem operasi 64 bit, pembagian tersebut digambarkan sebagai berikut: 64 bit
kernel space
47 bit user space 0 bit Gambar 1: Kernel Space dan User Space Linux 64 Bit Kernel adalah inti sistem operasi yang diload ke dalam memori sejak komputer booting. Kernel berperan mengendalikan prosesor, memori, disk drive, dan perangkat keras lainnya di dalam komputer. Demikian penting peran kernel sehingga harus ditempatkan dalam wilayah memori yang terproteksi sehingga tidak dapat dioverwrite oleh program aplikasi pengguna. Selanjutnya kita membatasi pembahasan pada user space. Dalam sistem operasi 64 bit, user space dapat diaddress dalam 47 bit, mencapai ukuran 128 Terabyte. User space dibagi dalam beberapa segmen. Segmen code berisi executable instruction dan konstanta global. Segmen data berisi variabel global yang diinisialisasi. Segmen bss (block started by symbol) berisi variabel global yang tidak diinisialisasi. Segmen heap berisi variabel yang dialokasikan secara dinamik. Segmen memorymapping berisi file mapping (termasuk dynamic library) dan anonymous mapping. Segmen stack berisi variabel dalam scope lokal yang dialokasikan secara otomatik3.
3
Alokasi memori secara otomatik dan dinamik dibahas lebih detail dalam bab berikutnya.
Linux System Programming in C
17
Datatrans Informatika
47 bit
stack memory-mapping heap bss data code
0 bit
Gambar 2: User Space Linux 64 Bit
4.2
Memeriksa User Space
Berikut ini adalah source code untuk memeriksa alokasi memori dalam user space. Listing 24. Memeriksa Layout Memori — job6.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
#include <stdio.h> #include <sys/types.h> #include const int global_const=20; int global_init=10; int global_uninit; int main(int argc, char* argv[]) { pid_t pid; int b=20; pid=getpid(); printf("pid %d\n", pid); printf("alamat main %p\n", &main); printf("alamat global_const %p\n", &global_const); printf("alamat global_init %p\n", &global_init); printf("alamat global_uninit %p\n", &global_uninit); printf("alamat b %p\n", &b); printf("ketik sembarang tombol:\n"); getchar(); return 0; }
Baris 1, menginclude stdio.h berisi deklarasi fungsi printf dan getchar. Baris 2 dan 3, menginclude sys/types.h dan unistd.h berisi deklarasi fungsi getpid. Baris 10, deklarasi variabel pid bertipe data pid_t untuk menyimpan nomor process id hasil eksekusi fungsi getpid (baris 13)4. Tipe data ini didefinisikan dalam file header /usr/include/sys/types.h sebagai berikut: typedef __pid_t pid_t;
Dalam file header /usr/include/bits/types.h, __pid_t didefinisikan sebagai berikut: __STD_TYPE __PID_T_TYPE __pid_t; 4
Linux memberi nomor id unik untuk setiap proses.
Linux System Programming in C
18
Datatrans Informatika
Dalam file header /usr/include/bits/typesize.h, __PID_T_TYPE didefinisikan sebagai berikut: #define __PID_T_TYPE
__S32_TYPE
Kembali dalam dalam file header /usr/include/bits/types.h, __S32_TYPE didefinsikan sebagai berikut: #define __S32_TYPE
int
Jadi, pid_t adalah alias untuk tipe data bilangan bulat int. Baris 14 sampai 19, deretan printf untuk memeriksa alamat variabelvariabel dalam memori. Baris 22, fungsi getchar menunda fungsi main tidak segera exit, menanti ketukan keyboard oleh pengguna. Dengan demikian, kita berkesempatan memeriksa alamat variabelvariabel. Mari mengenerate executable file job6: %
Alamat global_const (0x400750) berada dalam section rodata. Keduanya berada dalam segmen code. Alamat global_init (0x60104c) berada dalam section data dalam segmen data. Alamat global_uninit (0x601054) berada dalam section bss dalam segmen bss. Di manakah alamat b (0x7fff06c5d318)? Mari kita memeriksanya dalam file /proc/3961/maps5. % 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
Perhatian Process id (PID) akan berubah setiap kali ./job6 dieksekusi ulang. Sesuaikan lokasi file /proc//maps menurut process id terbaru. Dapat dilihat bahwa b (0x7fff06c5d318) berada dalam segment stack. Kesimpulan 1. Alokasi memori dibagi 2: kernel space dan user space. 2. Dalam user space, alokasi memori dibagi ke dalam segmen code, data, bss, heap, memorymapping dan stack. 3. Segmen code berisi executable instruction dan konstanta global. 4. Variabel dalam scope global yang diinisialisasi berada dalam segmen data. 5. Variabel dalam scope global yang tidak diinisialisasi berada dalam segmen BSS. 6. Variabel dalam scope lokal disimpan dalam segmen stack. Tugas Eksplorasi 1. Jika suatu konstanta diinisialisasi secara lokal dalam main, di segmen manakah konstanta tersebut berada?
5
Untuk setiap proses, Linux merekam detail alokasi memori dalam file dengan format /proc//maps.
Linux System Programming in C
20
Datatrans Informatika
5 Variabel dan Konstanta
Tujuan 1. Dapat mendeklarasikan, mengassign value dan menginisialisasi variabel. 2. Dapat menginisialisasi konstanta. 3. Dapat membedakan alamat dan nilai variabel. 4. Dapat membuktikan efek copy by value terhadap nilai dan alamat variabel. 5. Dapat memanfaatkan preprocessor DEFINE. Sebuah program terdiri atas 2 bagian: kode operasi dan data. Data yang dapat diubah disebut variabel. Sedangkan konstanta adalah data yang bernilai tetap.
5.1
Deklarasi Variabel
Dalam pemrograman C, setiap variabel atau konstanta harus dideklarasikan terlebih dahulu sebelum dapat dioperasikan. Deklarasi terdiri atas 2 hal: 1) nama variabel atau konstanta dan 2) tipe data. Listing 25. Deklarasi Variabel — job7a.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
#include <stdio.h> int main(int argc, char* argv[]) { int a; //deklarasi a=10;//assignment int b=20;//inisialisasi const int c=30; printf("a alamat %p nilai %d\n", &a, a); printf("b alamat %p nilai %d\n", &b, b); printf("c alamat %p nilai %d\n", &c, c); return 0; }
Baris 1, menginclude stdio.h untuk mendeklarasikan printf (digunakan pada baris 9 dan 10). Baris 4, variabel a dideklarasikan. Baris 5, variabel a diberi nilai (assignment). Baris 7, variabel b diinisialisasi (deklarasi sekaligus assignment). Baris 8, konstanta c diinisialisasi.
Linux System Programming in C
21
Datatrans Informatika
Baris 10, alamat a (diperiksa dengan sintaks &a) dan nilai a ditampilkan. Baris 11 dan 12: memeriksa hal yang sama untuk variabel b dan konstanta c. Mari mengenerate executable file job7a: %
gcc -o job7a -Wall job7a.c
Dan mengeksekusinya:
% ./job7a a alamat 0x7fff59a5450c nilai 10 b alamat 0x7fff59a54508 nilai 20 c alamat 0x7fff59a54504 nilai 30
5.2
Copy by Value
Mari menyelidiki efek pertukaran nilai dua variabel terhadap alamat dan nilai masingmasing. Listing 26. Copy by Value — job7b.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
#include <stdio.h> int main(int argc, char* argv[]) { int a=10; int b=20; printf("a alamat %p nilai %d\n", &a, a); printf("b alamat %p nilai %d\n", &b, b); b=a; printf("\nsetelah pertukaran nilai b=a\n"); printf("a alamat %p nilai %d\n", &a, a); printf("b alamat %p nilai %d\n", &b, b); a++; printf("\nperubahan nilai a setelah pertukaran\n"); printf("a alamat %p nilai %d\n", &a, a); printf("b alamat %p nilai %d\n", &b, b); return 0; }
Mari mengenerate executable file job7b: %
gcc -o job7b -Wall job7b.c
Dan mengeksekusinya:
% ./job7b a alamat 0x7fff654a526c nilai 10 b alamat 0x7fff654a5268 nilai 20 setelah pertukaran nilai b=a a alamat 0x7fff654a526c nilai 10 b alamat 0x7fff654a5268 nilai 10 perubahan nilai a setelah pertukaran a alamat 0x7fff654a526c nilai 11 b alamat 0x7fff654a5268 nilai 10
Variabel a dan b menempati alamat berbeda. Jika nilai kedua variabel dipertukarkan (baris 10) maka hanya nilai variabel tujuan (b) yang berubah (alamat tidak berubah) sebagaimana diperiksa pada baris 12 dan 13.
Linux System Programming in C
22
Datatrans Informatika
Karena pada dasarnya a dan b adalah 2 variabel yang berbeda alamat maka perubahan nilai a (baris 15) setelah pertukaran nilai tidak mengakibatkan perubahan nilai b sebagaimana diperiksa pada baris 17 dan 18.
5.3
Magic Number dan DEFINE
Magic number adalah istilah untuk bilangan yang muncul dalam kode program tanpa penjelasan. Listing 27. Magic Number — job7c.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
Baris 6, dalam fungsi main, variabel gdr diberi nilai 1. Di dalam fungsi print_gender, bilangan tersebut diperiksa untuk dikonversi menjadi string. Bagi fungsi main, bilangan 1 dan 2 (baris 9) adalah magic number. Kode program tersebut diperbaiki dengan memanfaatkan preprocessor DEFINE. Listing 28. Preprocessor DEFINE — job7d.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
Kini, kode gender menjadi lebih mudah dimengerti, baik dalam main maupun print_gender. Mari mengenerate executable file job7d: %
gcc -o job7d -Wall job7d.c
Dan mengeksekusinya: % ./job7d laki-laki perempuan
Kesimpulan 1. Variabel harus dideklarasikan sebelum dapat dioperasikan. 2. Copy by value hanya mengubah nilai variabel tujuan sedangkan alamatnya tetap. 3. Preprocessor DEFINE dapat digunakan untuk menghindari magic number. Tugas Eksplorasi 1. Gantilah preprocessor DEFINE (untuk MALE dan FEMALE) dengan konstanta. 2. Selidiki keuntungan menggunakan preprocessor DEFINE dibandingkan konstanta. Petunjuk: gunakan command line size untuk membandingkan ukuran executable file.
Linux System Programming in C
24
Datatrans Informatika
6 Pointer
Tujuan 1. Dapat mendeklarasikan, mengassign value dan menginisialisasi pointer. 2. Dapat mendereference pointer. 3. Dapat membuktikan efek copy by pointer terhadap alamat dan nilai variabel. 4. Dapat menerapkan pointer untuk memanipulasi array. 5. Dapat menggunakan pointer untuk memanipuasi string. Sesuai namanya, pointer adalah suatu variabel yang merujuk variabel lain.
6.1
Alamat dan Nilai Pointer
Sebagaimana variabel, pointer juga memiliki alamat memori dan nilai. Listing 29. Alamat dan Nilai Pointer — job8a.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
#include <stdio.h> int main(int argc, char* argv[]) { int a=10; int b=20; int* p;//deklarasi p sebagai pointer tipe data int p=&a;//pointer p merujuk a printf("alamat a %p nilai a %d\n", &a, a); printf("alamat p %p nilai p %p dereference %d\n", &p, p, *p); p=&b;//pointer p merujuk b printf("alamat b %p nilai b %d\n", &b, b); printf("alamat p %p nilai p %p dereference %d\n", &p, p, *p); int* s=&a; printf("alamat s %p nilai s %p dereference %d\n", &s, s, *s); return 0; }
Mari mengenerate executable file job8a: %
gcc -o job8a -Wall job8a.c
Dan mengeksekusinya:
% ./job8a alamat a 0x7fffbb3813fc alamat p 0x7fffbb3813f0 alamat b 0x7fffbb3813f8 alamat p 0x7fffbb3813f0
Baris 6, p dideklarasikan sebagai pointer untuk tipe data integer. Linux System Programming in C
25
Datatrans Informatika
Baris 7, pointer p merujuk variabel a. Pemeriksaan pada baris 10 menunjukkan 3 hal: • Pointer p memiliki alamat memori (0x7fffbb3813f0) yang berbeda dengan a (0x7fffbb3813fc). • Nilai p berisi alamat a (0x7fffbb3813fc). • Nilai a dapat diungkapkan dengan cara mendereferensi pointer p (sintaks: *p). Baris 12, pointer p berubah merujuk variabel b. Pemeriksaan pada baris 14 menunjukkan pola yang sama untuk b sebagaimana untuk a. Pada baris 16, pointer s diinisialisasi (deklarasi sekaligus assignment) merujuk variabel a.
6.2
Copy by Pointer
Jika suatu pointer telah merujuk kepada suatu variabel, apakah yang terjadi jika nilai variabel tersebut diubah. Listing 30. Copy By Pointer — job8b.c 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
#include <stdio.h> int main(int argc, char* argv[]) { int a=10; int* p=&a; printf("alamat a %p nilai a %d\n", &a, a); printf("alamat p %p nilai p %p dereference %d\n", &p, p, *p); a++; printf("\nnilai a diubah a++\n"); printf("alamat a %p nilai a %d\n", &a, a); printf("alamat p %p nilai p %p dereference %d\n", &p, p, *p); (*p)++; printf("\nperubahan melalui dereferensi p\n"); printf("alamat a %p nilai a %d\n", &a, a); printf("alamat p %p nilai p %p dereference %d\n", &p, p, *p); return 0; }
Mari mengenerate executable file job8b: %
gcc -o job8b -Wall job8b.c
Dan mengeksekusinya:
% ./job8b alamat a 0x7fffe098131c nilai a 10 alamat p 0x7fffe0981310 nilai p 0x7fffe098131c dereference 10 nilai a diubah a++ alamat a 0x7fffe098131c nilai a 11 alamat p 0x7fffe0981310 nilai p 0x7fffe098131c dereference 11 perubahan melalui dereferensi p alamat a 0x7fffe098131c nilai a 12 alamat p 0x7fffe0981310 nilai p 0x7fffe098131c dereference 12
Pointer p merujuk variabel a (baris 5). Perubahan nilai a terlihat juga melalui dereferensi p (baris 13).
Linux System Programming in C
26
Datatrans Informatika
Demikian juga, perubahan nilai melalui dereferensi p (baris 15) juga menyebabkan perubahan nilai a (baris 17). Tugas Explorasi Bagaimana jika kode pada baris 15 diubah dari (*p)++ menjadi *p++.
6.3
Array dan Pointer
Variabel yang merepresentasikan himpunan data disebut array. Pointer digunakan untuk mengakses array. Listing 31. Array — job8c.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
#include <stdio.h> int main(int argc, char* argv[]) { int a[3]; *(a+0)=10; *(a+1)=20; *(a+2)=30; printf("alamat a %p nilai a %p\n", &a, a); printf("mendereferensi pointer a\n"); printf("*(a+0) %d\n", *(a+0)); printf("*(a+1) %d\n", *(a+1)); printf("*(a+2) %d\n", *(a+2)); printf("\nnotasi yang lebih ringkas\n"); a[0]=40; a[1]=50; a[2]=60; printf("a[0] %d\n", a[0]); printf("a[1] %d\n", a[1]); printf("a[2] %d\n", a[2]); return 0; }
Mari mengenerate executable file job8c: %
gcc -o job8c -Wall job8c.c
Dan mengeksekusinya:
% ./job8c alamat a 0x7fffff4978a0 nilai a 0x7fffff4978a0 mendereferensi pointer a *(a+0) 10 *(a+1) 20 *(a+2) 30 notasi yang lebih ringkas a[0] 40 a[1] 50 a[2] 60
Variabel a adalah array berisi 3 integer (baris 4). Nilai array dimodifikasi melalui dereferensi pointer (baris 6 sampai 8). Alamat dan nilai array diperiksa pada baris 10 sampai 14. Pemeriksaan pada baris 10 menunjukkan bahwa nilai array a sama dengan alamatnya. Jadi a adalah pointer yang merujuk dirinya sendiri.
Linux System Programming in C
27
Datatrans Informatika
Array dapat dimodifikasi dan diperiksa menggunakan sintaks yang lebih ringkas (baris 17 sampai 22).
6.4
Inisialisasi Array
Tidak hanya dideklarasikan dan diberi nilai (assignment), array juga dapat diinisialisasi. Listing 32. Inisialisasi Array — job8d.c 1 2 3 4 5 6 7 8 9 10 11
Dan mengeksekusinya: % ./job8e s: ab, strlen 2 s[0] 61 a s[1] 62 b s[2] 0 s[3] 55 U s[4] FFFFFFFF �
mengubah elemen string sebelum terminating zero s: zb, strlen 2 s[0] 7A z s[1] 62 b s[2] 0 s[3] 55 U s[4] FFFFFFFF � mengubah elemen string setelah terminating zero s: zb, strlen 2 s[0] 7A z s[1] 62 b s[2] 0 s[3] 7A z
Baris 2: menginclude string.h berisi deklarasi untuk fungsi strcpy dan strlen (baris 9 dan 10). Baris 5: deklarasi array s berisi 5 elemen bertipe char. Baris 9: string “ab” disalin ke array s. Baris 10: n menyimpan panjang string s. String s dan elemenelemennya diperiksa pada baris 12 sampai 14. Baris 17: mengubah elemen array s pada posisi sebelum terminating zero. String s dan elemenelemennya diperiksa pada baris 19 sampai 21. Baris 24: mengubah elemen array s pada posisi setelah terminating zero. String s dan elemenelemennya diperiksa pada baris 26 sampai 28. Terlihat bahwa terminating zero adalah penghenti string. Setiap perubahan elemen setelah terminating zero diabaikan.
Linux System Programming in C
29
Datatrans Informatika
6.6
Inisialisasi String Bersumber dari Segmen Code
String dapat juga diinisialisasi (deklarasi sekaligus diberi nilai). Latihan berikut ini mencoba menginisialisasi string yang berasal dari segmen code. Listing 34. Inisialisasi String dari Segmen Code — job8f.c 1 2 3 4 5 6 7 8 9 10 11 12 13
Baris 5, string s diinisialisasi. Dalam kasus ini, s adalah pointer yang merujuk ke area dalam segmen code. Dibuktikan hasil pemeriksaan pada baris 9. Pointer s beralamat di stack (0x7fff29d43700) dan isinya merujuk ke alamat 0x400670 dalam section rodata, segmen code. % size -Ax job8f job8f : section .interp .note.ABI-tag .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .plt .text .fini .rodata .eh_frame_hdr .eh_frame .init_array .fini_array .jcr .dynamic .got .got.plt .data .bss .comment
Bagaimana jika mencoba mengubah elemen yang berada dalam segmen code? Listing 35. Mengubah String dalam Segmen Code — job8g.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
% ./job8h s: alamat 0x7fff0fe70930 ps: alamat 0x7fff0fe70928, nilai 0x7fff0fe70930 ps: ab mengubah elemen string sebelum terminating zero ps: zb
Baris 5: mendeklarasikan array s di segmen stack. Baris 6: menyalin string “ab” ke string s. Baris 8: pointer ps diinisialisasi merujuk ke string s. Baris 10 sampai 12: memeriksa alamat dan nilai pointer ps. Baris 15: mengubah elemen string yang berada dalam stack. Berbeda dengan latihan sebelumnya, kali ini elemen string berhasil diubah.
6.8
Pointer Konstan
Apa yang terjadi jika pointer konstan merujuk suatu variabel? Dapatkah mengubah nilai variabel melalui dereferensi pointer tersebut? Listing 37. Pointer Konstan — job8i.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
Baris 8, pointer ps diinisialisasi secara konstan. Mari mengenerate executable file job8i:
% gcc -o job8i -Wall job8i.c job8h.c: In function ‘main’: job8h.c:15:2: error: assignment of read-only location ‘*ps’ ps[0]='z'; ^
Kompilasi gagal. Baris 15: mencoba mengubah nilai melalui dereferensi pointer konstan. Kesimpulan 1. Pointer adalah variabel yang nilainya berisi alamat variabel lain. 2. Pointer dapat digunakan untuk merepresentasikan array.
Linux System Programming in C
32
Datatrans Informatika
3. Nilai variabel yang dirujuk oleh pointer dapat diakses maupun diubah melalui dereferensi pointer. 4. Kecuali untuk pointer konstan, tidak dapat digunakan untuk mengubah nilai variabel yang dirujuk. Tugas Explorasi Setelah mengetahui cara kerja pointer. Cobalah memehami perbedaan NULL dengan 0.
Linux System Programming in C
33
Datatrans Informatika
III Tipe Data
7 Tipe Data Dasar 8 Structure 9 Byte Alignment 10 Union
Linux System Programming in C
34
Datatrans Informatika
7 Tipe Data Dasar
Tujuan 1. Mengetahui banyaknya byte tipetipe data dasar. 2. Mengetahui nilai batas tipetipe data dasar. Variabel atau konstanta dideklarasikan dengan cara menentukan nama dan tipe datanya. Tiap tipe data memiliki ukuran banyaknya byte alokasi memori dan batas nilai minimum dan maksimum. Agar hemat alokasi memori, alangkah baiknya memilih tipe data sesuai kebutuhan. Banyaknya byte dan batas minimum maksimum tipe data tergantung sistem operasi. Listing 38. Ukuran dan Batas Tipe Data — job9a.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
#include <stdio.h> #include int main(int argc, char* argv[]) { printf("char\t\tsize %lu, min %d, max %d\n", sizeof(char), CHAR_MIN, CHAR_MAX); printf("unsigned char\tsize %lu, max %d\n", sizeof(unsigned char), UCHAR_MAX); printf("short\t\tsize %lu, min %d, max %d\n", sizeof(short), SHRT_MIN, SHRT_MAX); printf("unsigned short\tsize %lu, max %d\n", sizeof(unsigned short), USHRT_MAX); printf("int\t\tsize %lu, min %d, max %d\n", sizeof(int), INT_MIN, INT_MAX); printf("unsigned int\tsize %lu, max %u\n", sizeof(unsigned int), UINT_MAX); printf("long\t\tsize %lu, min %ld, max %lu\n", sizeof(long), LONG_MIN, LONG_MAX); printf("unsigned long\tsize %lu, max %lu\n", sizeof(unsigned long), ULONG_MAX); printf("long long\tsize %lu, min %lld, max %llu\n", sizeof(long long), LLONG_MIN, LLONG_MAX); printf("unsigned long long\tsize %lu, max %llu\n", sizeof(unsigned long long), ULLONG_MAX); printf("float\t\tsize %lu, min %e, max %e\n", sizeof(float), FLT_MIN, FLT_MAX); printf("double\t\tsize %lu, min %e, max %e\n", sizeof(double), DBL_MIN, DBL_MAX); printf("long double\tsize %lu, min %Le, max %Le\n", sizeof(long double), LDBL_MIN, LDBL_MAX); Return 0; }
Linux System Programming in C
35
Datatrans Informatika
Mari mengenerate executable file job9a: %
gcc -o job9a -Wall job9a.c
Dan mengeksekusinya:
% ./job9a char size 1, min -128, max 127 unsigned charsize 1, max 255 short size 2, min -32768, max 32767 unsigned short size 2, max 65535 int size 4, min -2147483648, max 2147483647 unsigned int size 4, max 4294967295 long size 8, min -9223372036854775808, max 9223372036854775807 unsigned longsize 8, max 18446744073709551615 long long size 8, min -9223372036854775808, max 9223372036854775807 unsigned long long size 8, max 18446744073709551615 float size 4, min 1.175494e-38, max 3.402823e+38 double size 8, min 2.225074e-308, max 1.797693e+308 long double size 16, min 3.362103e-4932, max 1.189731e+4932
Baris 2: menginclude values.h berisi deklarasi untuk simbolsimbol CHAR_MIN, CHAR_MAX dan seterusnya. Baris 6: banyaknya byte suatu tipe data diketahui menggunakan fungsi sizeof. Kesimpulan Pemilihan tipe data berkaitan dengan banyaknya byte dan nilai minimum dan maksimum. Tugas Explorasi 1. Apa yang terjadi jika suatu variabel diberi nilai melebihi batas tipe datanya? 2. Banyaknya byte, nilai minimum dan maksimum suatu tipe data dapat berbeda antar sistem operasi. Dalam kasus tertentu, batasbatas tersebut diharuskan konsisten. Apa yang harus dilakukan? 3. Dapatkah nilai suatu variabel bertipe short dibaca sebagai integer? Demikian juga sebaliknya? 4. Bagaimana cara menjumlahkan dua variabel bertipe data berbeda tanpa kehilangan kepresisian?
Linux System Programming in C
36
Datatrans Informatika
8 Structure
Tujuan 1. Dapat mendeklarasikan structure. 2. Dapat mendeklarasikan dan menginisialisasi variabel bertipe structure. 3. Dapat mengubah dan mengakses variabel bertipe structure. 4. Dapat menggunakan pointer untuk mengubah dan mengakses variabel bertipe structure. Variabelvariabel dengan tipe data dasar dapat disusun menjadi suatu structure. Listing 39. Deklarasi Structure — job9b.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
Baris 3 sampai 6: deklarasi structure bernama point terdiri atas x dan y. Baris 10: deklarasi variabel p1 bertipe structure point. Baris 11: memeriksa ukuran dan alamat p1. Ukuran structure point (8 byte) adalah akumulasi ukuran elemenelemennya (x 4 byte adan y 4 byte). Alamat elemen pertama (x) sama dengan alamat structure (0x7fff189fd240). Perhatian Ukuran suatu structure tidak selalu eksak sama dengan akumulasi ukuran elemen elemennya. Hal ini dijelaskan dalam byte alignment. Baris 13 dan 14: cara mengubah nilai elemenelemen variabel p1. Baris 15: cara mengakses elemenelemen variabel p1 untuk ditampilkan di layar komputer. Baris 17: menginisialisasi variabel p2 bertipe structure point. Baris 20: menginisialisasi pointer p3 untuk merujuk p2. Baris 21 dan 22: mengubah variabel p2 melalui pointer p3. Perhatikan penggunaan tanda →. Baris 24: mengakses elemen variabel p2 melalui pointer p3. Kesimpulan 1. Structure terdiri atas susunan elemenelemen. 2. Structure memudahkan organisasi data. 3. Ukuran structure adalah sama dengan atau lebih dari akumulasi ukuran elemen elemennya. Tugas Explorasi 1. Bagaimana membuat structure berisi elemen string. Apakah menggunakan tipe char* atau char[n]? 2. Structure tidak hanya berisi elemenelemen dengan tipe data dasar. Buatlah structure garis berisi dua buah elemen bertipe structure point. Bagaimana cara meginisialisasi, mengubah dan mengakses elemenelemennya?
Linux System Programming in C
38
Datatrans Informatika
9 Byte Alignment
Tujuan 1. Memahami efek byte alignment terhadap ukuran structure dan alamat elemennya. 2. Dapat mengatur byte alignment tertentu. Ukuran structure tidak selalu eksak sama dengan akumulasi elemenelemennya.
Baris 14 sampai 16: ukuran structure nilai (16) melebihi akumulasi ukuran elemenelemennya (11). Berdasarkan pemeriksaan baris 20 sampai 23, elemenelemen nilai dipetakan sebagai berikut: a.simbol
Baris 3: membackup byte alignment untuk direstore pada baris 11. Baris 4: mengatur byte alignment sebesar 1 byte. Baris 17 sampai 20: ukuran structure nilai (11 byte) sama dengan akumulasi ukuran elemen elemennya. Berdasarkan pemeriksaan baris 22 sampai 25, elemenelemen nilai dipetakan sebagai berikut: a.simbol
Kesimpulan 1. Ukuran structure dapat melebihi akumulasi ukuran elemenelemennya karena byte aligment. 2. Byte alignment dapat diatur menggunakan preprocessor PRAGMA. Tugas Explorasi Linux System Programming in C
41
Datatrans Informatika
1. Mengapa byte alignment diperlukan? 2. Temukan kasus penggunaan structure tanpa extra byte padding sehingga preprocessor PRAGMA harus digunakan.
Linux System Programming in C
42
Datatrans Informatika
10 Union
Tujuan 1. Dapat membedakan union dengan structure. 2. Dapat mendeklarasikan union. 3. Dapat mengubah dan mengakses variabel bertipe union. 4. Dapat menggunakan pointer untuk mengubah dan mengakses variabel bertipe union. Sebagaimana structure, union digunakan untuk mengemas elemenelemen dalam suatu tipe data yang kompak. Mari mempelajari perbedaan structure dan union. Listing 42. Mengatur Union — job9e.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
Baris 4 sampai 7: deklarasi union bernama idcard terdiri atas elemen ktp dan passort. Baris 11: memeriksa ukuran union idcard: 20 byte, sama dengan elemen terpanjang (ktp). Baris 13: deklarasi variabel id bertipe union idcard. Baris 14 sampai 16: memeriksa alamat elemenelemen union. Ternyata, alamat ktp sejajar dengan passport. Berdeda dengan structure yang menyusun elemenelemennya secara serial. Baris 18: string “123456789” disalin untuk elemen ktp. Pemeriksaan baris 19 dan 20 menunjukkan bahwa passport ikut berubah. Baris 22: string “ABCDEFGHI” disalin untuk elemen passport. Pemeriksaan baris 23 dan 24 menunjukkan bahwa ktp ikut berubah. Baris 26: menginisialisasi pointer p untuk merujuk variabel id. Baris 27: mengubah elemen ktp melalui pointer p. Perhatikan penggunaan tanda →. Baris 28 dan 29: mengakses elemen variabel id melalui pointer p. Kesimpulan 1. Ukuran suatu union adalah ukuran elemen yang terbesar. Berbeda dengan ukuran structure yang merupakan akumulasi ukuran elemenelemennya. 2. Dengan jumlah dan tipe data elemenelemen yang sama, union lebih hemat memori dibandingkan structure. 3. Union menyusun elemenelemennya secara sejajar. Berbeda dengan structure yang menyusun elemenelemennya secara serial. Tugas Explorasi 1. Dapatkah suatu union berisi elemen structure? Demikian pula sebaliknya. 2. Dalam kasus apa union diperlukan?
Linux System Programming in C
44
Datatrans Informatika
IV Alokasi Memori
11 Alokasi Memori di Stack 12 Alokasi Memori di Heap
Linux System Programming in C
45
Datatrans Informatika
11 Alokasi Memori di Stack
Tujuan 1. Mengetahui Batas Alokasi Memori di Stack. 2. Membuktikan Pengalamatan Mundur dalam Alokasi Memori di Stack. 3. Membuktikan Penghapusan Variabel dari Memori Stack secara Otomatik. Pada bagian sebelumnya kita sudah mempelajari layout memori, terutama user space6.
11.1
Batas Alokasi Memori di Stack
Kita dapat mengetahui batas alokasi memori di stack dengan perintah sebagai berikut: % ulimit -s 8192
Ukuran stack adalah 8192 kilobyte atau 8 megabyte. Mari menguji ukuran stack dengan source code berikut ini. Listing 43. Menguji Batas Alokasi Memori di Stack (Fase 1) — job10a.c 1 2 3 4 5 6 7 8 9 10 11
Baris 7, a adalah array berisi 5 mega elemen (lihat definisi ARRAY_SiZE pada baris 4) bertipe data char. Karena setiap tipe data char berukuran 1 byte maka a membutuhkan alokasi memori sebanyak 5 megabyte. Baris 8, fungsi memset bertugas mengisi array a dengan bilangan 0. Mari mengenerate executable file: %
gcc -o job10a -Wall job10a.c
Lalu mengeksekusinya: % ./job10a alokasi a berhasil
Alokasi array a berhasil karena belum melampaui batas stack 8 megabyte. Selanjutnya, mari kita menambahkan array b ke dalam source code job10b.c. 6
Lalu mengeksekusinya: % ./job10b Segmentation fault
Kali ini alokasi memori gagal karena total array a dan b melampaui batas stack 8 megabyte.
11.2
Scope dan Daur Hidup Variabel
Setiap variabel dalam scope lokal dideklarasikan dalam stack7. Alokasi tersebut bersifat otomatik karena variabel dihapus dari memori (dealokasi) ketika keluar scope. Mari meninjau kembali source code job7b.c. Bagaimana jika array a dan b ditempatkan dalam sub scope: Listing 45. Dealokasi Memori Otomatik — job10c.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
Kecuali jika dideklarasikan menggunakan malloc yang akan dijelaskan kemudian.
Linux System Programming in C
47
Datatrans Informatika
Perhatikan bahwa array a dideklarasikan dalam sub scope baris 9 sampai 11. Array b dideklarasikan dalam sub scope baris 15 sampai 17. Ketika keluar dari sub scope variabel a didealokasikan dari memori (baris 12). Demikian juga dengan variabel b (baris 18). Mengenerate executable file: %
gcc -o job10c -Wall job10c.c
Mengeksekusinya:
% ./job10c alokasi a berhasil alokasi b berhasil
Baik array a maupun b berhasil dialokasikan karena dalam sub scope masingmasing hanya dibutuhkan alokasi memori 5 megabyte.
11.3
Pengalamatan Mundur
Source code berikut ini berisi tiga variabel dalam scope lokal yang dialokasikan dalam stack. Listing 46. Pengalamatan Mundur — job10d.c 1 2 3 4 5 6 7 8 9 10 11 12 13
#include <stdio.h> int main(int argc, char* argv[]) { int a=10; int b=20; int c=30; printf("a alamat %p nilai %d\n", &a, a); printf("b alamat %p nilai %d\n", &b, b); printf("c alamat %p nilai %d\n", &c, c); return 0; }
Mengenerate executable file: %
gcc -o job10d -Wall job10d.c
Mengeksekusinya:
% ./job10d a alamat 0x7fffc9a6800c nilai 10 b alamat 0x7fffc9a68008 nilai 20 c alamat 0x7fffc9a68004 nilai 30
Terlihat bahwa pengalamatan variabel a, b dan c dilakukan secara mundur. Variabel a yang pertama diinisialisasi (baris 4) memperoleh alamat tertinggi ( 0x7fffc9a6800c). Sedangkan variabel c yang terakhir diinisialisasi (baris 6) memperoleh alamat terendah (0x7fffc9a68004). Alamat variabel a, b dan c terpaut 4 byte sesuai ukuran tipe data integer. Kesimpulan 1. Variabel yang dialokasikan dalam stack diberi alamat mundur. 2. Ukuran alokasi memori di stack tidak dapat melampaui batas yang ditetapkan sistem operasi. 3. Variabel yang dialokasikan dalam stack secara otomatik didealokasikan dari memori ketika keluar dari scope.
Linux System Programming in C
48
Datatrans Informatika
12 Alokasi Memori di Heap
Tujuan 1. Dapat mengalokasikan memori di heap. 2. Membuktikan Pengalamatan Maju dalam Alokasi Memori di Heap. 3. Dapat mengatur nilai variabel yang dialokasikan dalam heap. 4. Dapat mendealokasikan memori di heap. Ukuran RAM komputer masa kini umumnya dalam orde gigabyte. Jauh melampaui batas alokasi memori di stack (8 megabyte). Dalam bab ini kita akan mencoba memanfaatkan sumber daya memori yang melimpah tersebut agar dapat menanggulangi keterbatasan alokasi memori di stack. stack memory-mapping alokasi
heap bss data code Gambar 3: Alokasi Memori di Heap dan Pointer di Stack Pengalokasian memori di heap melibatkan 2 segmen: stack dan heap. Setelah berhasil mengalokasikan memori di heap, alamat awalnya disimpan dalam pointer8 yang berada dalam stack. Pointer tersebut dibutuhkan untuk menulis dan membaca data dari segmen heap. Selain itu, pointer tersebut dibutuhkan untuk mendealokasikan memori dari heap. Tidak seperti alokasi memori otomatik di stack, dealokasi memori di heap harus dilakukan secara eksplisit. Listing 47. Alokasi Memori di Heap — job10e.c 1 2 3 4 5 6 7 8 8
#include #include #include #include #include
<stdlib.h> <string.h> <stdio.h> <sys/types.h>
int main(int argc, char* argv[]) { pid_t pid=getpid(); Mengenai pointer akan dijelaskan kemudian.
Linux System Programming in C
49
Datatrans Informatika
9 10 11 12 13 14 15 16 17 18 19 20
printf("pid %d\n", pid); char* p=(char*)malloc(10*1024*1024*sizeof(char)); printf("alamat p %p\n", &p); printf("alamat awal alokasi di heap %p\n", p); strcpy(p, "alokasi di heap"); printf("%s\n", p); printf("%s\n", p+11); printf("ketik sembarang kunci"); getchar(); free(p); return 0; }
Baris 8, membaca process id untuk memeriksa detail alokasi memori dalam file /proc//maps. Baris 10, alokasi memori di heap sebanyak 10 megabyte. Alamat awalnya disimpan dalam pointer p yang berada dalam stack. Baris 11, memeriksa alamat pointer dalam segmen stack. Baris 12, memeriksa alamat awal alokasi memori di heap. Baris 13, memanfaatkan pointer untuk menulis string alokasi di heap ke dalam memori di heap. Baris 14, memanfaatkan pointer untuk membaca string sejak alamat pertama (terbaca: alokasi di heap). Baris 15, memanfaatkan pointer untuk membaca string pada offset 11 (terbaca: heap). Baris 17, break untuk mengambil kesempatan memeriksa detail alokasi memori. Proses akan diresume jika kita mengetik sembarang tombol keyboard. Baris 18, memanfaatkan pointer untuk mendealokasikan memori dari heap. Mengenerate executable file: %
gcc -o job10e -Wall job10e.c
Mengeksekusinya:
% ./job10e pid 5188 alamat p 0x7fffdc75e9d0 alamat awal alokasi di heap 0x7fee40ccd010 alokasi di heap heap ketik sembarang kunci
Setelah mengetahui process id 5188, mari memeriksa detaill alokasi memori. Tanpa mengetik sembarang kunci, aktifkan console baru. Periksa file /proc/5188/maps. % 1 2 3 4 5 6 7 8
Mari membandingkan printout ./job8 dengan detail alokasi memori: • Alamat p 0x7fffdc75e9d0 berada dalam segmen stack (baris 16). • Alamat awal alokasi di heap 0x7fee40ccd010 berada dalam segmen heap (baris 4). Kesimpulan 1. Alokasi memori di heap bersifat dinamik. Dealokasinya harus dilakukan secara eksplisit. 2. Alamat awal alokasi memori di heap disimpan dalam pointer yang berada dalam stack. Pointer tersebut digunakan untuk menulis dan membaca data dari memori di heap. Selain itu, pointer tersebut digunakan untuk mendealokasikan memori dari heap. Tugas Eksplorasi 1. Bagaimana cara mengalokasikan variabel bertipe structure dalam heap? 2. Bagaimana cara mengatur nilai elemen structure yang dialokasikan di heap? 3. Bagaimana mengubah ukuran alokasi memori di heap? 4. Dalam kasus apakah ukuran alokasi memori di heap perlu diubah?
Linux System Programming in C
51
Datatrans Informatika
V Function Argument Passing
13 Argument Passing by Value 14 Argument Passing by Pointer 15 Callback Function
Linux System Programming in C
52
Datatrans Informatika
13 Argument Passing by Value
Tujuan 1. Dapat mendeklarasikan dan mendefinisikan fungsi dengan argumen yang dipersiapkan untuk passing by value. 2. Dapat mengirimkan argumen ke fungsi secara passing by value. 3. Memahami efek perubahan nilai argumen fungsi terhadap nilai variabel dalam fungsi pemanggilnya. Suatu fungsi adalah unit operasi yang menerima input dan menghasilkan output. Input dikirimkan melalui argumen, dapat berupa nilai maupun alamat. Jika yang dikirimkan adalah nilai maka disebut passing by value. Listing 48. Passing by Value — job11a.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
#include <stdio.h> int add(int, int); int main(int argc, char* argv[]){ int n1, n2, m; n1=10; n2=20; printf("sebelum add, alamat n1 %p, nilai %d\n", &n1, n1); printf("sebelum add, alamat n2 %p, nilai %d\n\n", &n2, n2); m=add(n1, n2); printf("\nsetelah add, alamat n1 %p, nilai %d\n", &n1, n1); printf("setelah add, alamat n2 %p, nilai %d\n", &n2, n2); printf("setelah add, nilai m %d\n\n", m); return 0; } int add(int a, int b) { int sum=a+b; a++; b++; printf("di dalam fungsi add, alamat a %p nilai a %d\n", &a, a); printf("di dalam fungsi add, alamat b %p nilai b %d\n", &b, b); return sum; }
Mengenerate executable file: %
gcc -o job11a -Wall job11a.c
Mengeksekusinya:
% ./job11a sebelum add, alamat n1 0x7fff9d086bd8, nilai 10 sebelum add, alamat n2 0x7fff9d086bd4, nilai 20
Linux System Programming in C
53
Datatrans Informatika
di dalam fungsi add, alamat a 0x7fff9d086b9c nilai a 11 di dalam fungsi add, alamat b 0x7fff9d086b98 nilai b 21 setelah add, alamat n1 0x7fff9d086bd8, nilai 10 setelah add, alamat n2 0x7fff9d086bd4, nilai 20 setelah add, nilai m 30
Baris 3: forward declaration untuk fungsi add, dua argumen input bertipe int dan return bertipe int. Baris 6: deklarasi variabel n1, n2 dan m bertipe integer. Baris 7 dan 8: variabel n1 dan n2 masingmasing diberi nilai 10 dan 20 (assignment). Baris 9 dan 10: memeriksa alamat dan nilai variabel n1 dan n2 sebelum pemanggilan fungsi add. Baris 11: memanggil fungsi add. Instruction pointer dialihkan dari main ke fungsi add (baris 18). Nilai variabel n1 dan n2 masingmasing disalin ke argumen a dan b. Baris 19: variabel sum diinisialisasi berisi hasil penjumlahan argumen a dan b. Baris 20 dan 21: nilai Argumen a dan b diincrement (ditambah 1). Terkait penjelasan baris 11 (nilai argumen a dan b disalin dari nilai variabel n1 dan n2), apakah n1 dan n2 juga berubah? Baris 22 dan 23: memeriksa alamat dan nilai argumen a dan b. Alamat argumen a dan b berbeda dengan variabel n1 dan n2. Baris 24: fungsi add mereturn nilai variabel sum. Instruction pointer dialihkan dari fungsi add ke main (baris 12). Baris 12 sampai 14: memeriksa nilai variabel n1, n2 dan m setelah fungsi add. Ternyata tidak berubah (menjawab pertanyaan pada penjelasan baris 20 dan 21). Kesimpulan 1. Argument passing by value menyalin nilai variabel fungsi pemanggil bagi argumen fungsi yang dipanggil. 2. Perubahan argumen fungsi tidak mengubah nilai variabel fungsi pemanggil. Tugas Eksplorasi 1. Buatlah fungsi dengan argumen bertipe structure. Lakukan pemanggilan fungsi dengan cara argument passing by value. 2. Apa manfaat dan kerugian argument passing by value?
Linux System Programming in C
54
Datatrans Informatika
14 Argument Passing by Pointer
Tujuan 1. Dapat mendeklarasikan dan mendefinisikan fungsi dengan argumen yang dipersiapkan untuk passing by pointer. 2. Dapat mengirimkan argumen ke fungsi secara passing by pointer. 3. Memahami efek perubahan nilai argumen fungsi terhadap nilai variabel dalam fungsi pemanggilnya. Suatu fungsi adalah unit operasi yang menerima input dan menghasilkan output. Input dikirimkan melalui argumen, dapat berupa nilai maupun alamat. Jika yang dikirimkan adalah alamat maka disebut passing by pointer. Listing 49. Passing by Pointer — job11b.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
#include <stdio.h> int add(int*, int*); int main(int argc, char* argv[]){ int n1, n2, m; n1=10; n2=20; printf("sebelum add, alamat n1 %p, nilai %d\n", &n1, n1); printf("sebelum add, alamat n2 %p, nilai %d\n\n", &n2, n2); m=add(&n1, &n2); printf("\nsetelah add, alamat n1 %p, nilai %d\n", &n1, n1); printf("setelah add, alamat n2 %p, nilai %d\n", &n2, n2); printf("setelah add, nilai m %d\n\n", m); return 0; } int add(int* a, int* b) { int sum=*a+*b; (*a)++; (*b)++; printf("di dalam fungsi add, alamat a %p nilai a %d\n", &a, *a); printf("di dalam fungsi add, alamat b %p nilai b %d\n", &b, *b); return sum; }
Mengenerate executable file: %
gcc -o job11b -Wall job11b.c
Mengeksekusinya:
% ./job11b sebelum add, alamat n1 0x7fff84b7f228, nilai 10 sebelum add, alamat n2 0x7fff84b7f224, nilai 20
Linux System Programming in C
55
Datatrans Informatika
di dalam fungsi add, alamat a 0x7fff84b7f1e8 nilai a 11 di dalam fungsi add, alamat b 0x7fff84b7f1e0 nilai b 21 setelah add, alamat n1 0x7fff84b7f228, nilai 11 setelah add, alamat n2 0x7fff84b7f224, nilai 21 setelah add, nilai m 30
Baris 3: forward declaration untuk fungsi add, dua argumen input bertipe pointer integer (int*) dan return bertipe int. Baris 6: deklarasi variabel n1, n2 dan m bertipe integer. Baris 7 dan 8: variabel n1 dan n2 masingmasing diberi nilai 10 dan 20 (assignment). Baris 9 dan 10: memeriksa alamat dan nilai variabel n1 dan n2 sebelum pemanggilan fungsi add. Baris 11: memanggil fungsi add. Instruction pointer dialihkan dari main ke fungsi add (baris 18). Alamat variabel n1 dan n2 masingmasing disalin ke argumen a dan b. Baris 19: variabel sum diinisialisasi berisi hasil penjumlahan nilai yang dirujuk argumen pointer a dan b. Karena a dan b adalah pointer maka nilai diakses menggunakan dereferensi (*a dan *b). Baris 20 dan 21: nilai dereferensi a dan b diincrement (ditambah 1). Terkait penjelasan baris 11 (argumen pointer a dan b merujuk variabel n1 dan n2), apakah n1 dan n2 juga berubah? Baris 22 dan 23: memeriksa alamat dan nilai dereferensi argumen a dan b. Alamat argumen a dan b berbeda dengan variabel n1 dan n2. Baris 24: fungsi add mereturn nilai variabel sum. Instruction pointer dialihkan dari fungsi add ke main (baris 12). Baris 12 sampai 14: memeriksa nilai variabel n1, n2 dan m setelah fungsi add. Ternyata berubah (menjawab pertanyaan pada penjelasan baris 20 dan 21). Kesimpulan 1. Argument passing by pointer menyalin alamat variabel fungsi pemanggil bagi argumen fungsi yang dipanggil. 2. Perubahan dereferensi argumen fungsi mengubah nilai variabel fungsi pemanggil. Tugas Eksplorasi 1. Buatlah fungsi yang mengirimkan dua output, satu melalui return dan yang lain melalui argumen. 2. Buatlah fungsi untuk swap dua variabel. 3. Buatlah fungsi dengan argumen bertipe structure. Lakukan pemanggilan fungsi dengan cara argument passing by pointer. 4. Apa manfaat dan kerugian argument passing by pointer? 5. Bagaimana mencegah suatu fungsi agar tidak dapat mengubah nilai argumen yang dikirimkan dengan cara passing by pointer.
Linux System Programming in C
56
Datatrans Informatika
15 Callback Function
Tujuan 1. Dapat mendeklarasikan dan mendefinisikan fungsi dengan argumen berupa callback function. 2. Dapat mengirimkan fungsi sebagai argumen fungsi lain. Tidak hanya variabel, sebuah fungsi dapat memiliki argumen berupa fungsi. Listing 50. Callback Function — job11c.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
#include <stdio.h> void set_data( void (*f) (int, int) ); void add_and_print_data(int, int); int main(int argc, char* argv[]) { set_data(add_and_print_data); return 0; } void set_data( void (*f) (int, int) ) { int n1=10; int n2=20; f(n1, n2); } void add_and_print_data(int a, int b) { int c=a+b; printf("sum=%d\n", c); }
Mengenerate executable file: %
gcc -o job11c -Wall job11c.c
Mengeksekusinya: % ./job11c sum=30
Baris 3: forward declaration fungsi set_data. Perhatikan notasi argumen untuk callback function. Baris 4: forward declaration fungsi add_and_print_data yang akan dirimkan bagi fungsi set_data. Perhatikan tipe argumenargumen dan tipe returnnya harus sesuai dengan spesifikasi yang ditetapkan fungsi set_data. Baris 7: memanggil fungsi set_data, mengirimkan fungsi add_and_print_data sebagai argumen.
Linux System Programming in C
57
Datatrans Informatika
Baris 12 dan 13: inisialiasai n1 dan n2. Baris 14: memanggil callback function dan mengirimkan n1 dan n2 sebagai argumen. Baris 18: di dalam callback function, variabel c diinisialisasi berisi nilai penjumlahan argumen a dan b. Baris 19: nilai c ditampilkan di layar. Kesimpulan 1. Argumen fungsi dapat berupa fungsi lain. 2. Tipe data argumen dan return suatu callback function yang dikirimkan sebagai argumen harus cocok sebagaimana ditetapkan oleh fungsi yang membutuhkannya. Tugas Eksplorasi 1. Buatlah fungsi sorting bilangan secara ascending yang disusun dalam sebuah array. 2. Buatlah fungsi sorting bilangan secara descending yang disusun dalam sebuah array. 3. Modifikasilah fungsifungsi tersebut. Komparasi bilangan untuk memutuskan ordering secara ascending maupun descending dilakukan oleh callback function.
Linux System Programming in C
58
Datatrans Informatika
VI Library
16 Static Link Source Code 17 Static Link Object Code 18 Static Link Archive 19 Dynamic Link Shared Object
Linux System Programming in C
59
Datatrans Informatika
16 Static Link Source Code
Tujuan 1. Dapat membuat library yang dilink secara statik di tingkat source code. 2. Memahami keuntungan dan kerugian link statik tingkat source code. Logic yang potensial digunakan berulangulang dalam berbagai projek dikemas dalam library. Library lalu dilink dengan main module dengan beberapa cara. Mari mulai dengan mengeksplorasi static link di tingkat source code. Kita akan membuat library berisi fungsifungsi statistik. Source code disusun dalam layout direktori sebagai berikut:
Gambar 4: Layout Direktori Library dan Main Module Library dilink secara permanen dengan main module ketika aplikasi dibuild.
16.1
Library
File header library adalah sebagai berikut: Listing 51. Header Library — stat.h 1 2 3 4 5 6
Definisi library adalah sebagai berikut: Listing 52. Definisi Library — stat.c 1 2 3 4 5 6 7
#include <stdio.h> static int sum(const int*, int); double mean(const int* data, int size) { printf("address sum dalam library %p\n", &sum); int total=sum(data, size);
Linux System Programming in C
60
Datatrans Informatika
8 9 10 11 12 13 14 15 16
return total/(double)size; } static int sum(const int* data, int size) { int n=0, i; for(i=0;i<size;i++) n+=data[i]; return n; }
Di dalam direktori berisi Makefile, ketik command line berikut ini untuk mengenerate executable file: %
make
Mengeksekusinya:
% ./app address main 0x400530 address sum dalam library 0x400609 average 3.000000
Berdasarkan hasil eksekusi, fungsi main dan fungsi sum dalam library berada dalam segmen yang sama: % size -Ax app app : section .interp .note.ABI-tag .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn 9
Kesimpulan 1. Jika library dilink secara statik dengan main module, alamat fungsi library berada dalam segmen yang sama dengan main module, yaitu code segment. 2. Besarnya ukuran aplikasi ditentukan main module dan library. Tugas Eksplorasi 1. Diskusikan keuntungan dan kerugian library yang dilink secara statik dengan main module di tingkat source code. 2. Tambahkan fungsi standard deviasi ke dalam library. 3. Tambahkan fungsi median ke dalam library.
Linux System Programming in C
62
Datatrans Informatika
17 Static Link Object Code
Tujuan 1. Dapat membuat library yang dilink secara statik di tingkat object code. 2. Memahami keuntungan dan kerugian link statik tingkat object code. Kali ini library statistik disajikan bagi main module bukan berupa source code (stat.c) tetapi berupa object code (stat.o). Source code disusun dalam layout direktori sebagai berikut:
Gambar 5: Layout Direktori Library dan Main Module Karena library dibuild terpisah dari main module maka memiliki Makefile sendiri. Library di link secara permanen dengan main module ketika aplikasi dibuild.
17.1
Library
File header library adalah sebagai berikut: Listing 55. Header Library — stat.h 1 2 3 4 5 6
Definisi library adalah sebagai berikut: Listing 56. Definisi Library — stat.c 1 2 3 4 5 6 7 8
#include <stdio.h> static int sum(const int*, int); double mean(const int* data, int size) { printf("address sum dalam library %p\n", &sum); int total=sum(data, size); return total/(double)size;
Linux System Programming in C
63
Datatrans Informatika
9 10 11 12 13 14 15 16
} static int sum(const int* data, int size) { int n=0, i; for(i=0;i<size;i++) n+=data[i]; return n; }
Makefile adalah sebagai berikut: Listing 57. Makefile 1 2 3 4
% ./app address main 0x400530 address sum dalam library 0x400609 average 3.000000
Berdasarkan hasil eksekusi, fungsi main dan fungsi sum dalam library berada dalam segmen yang sama: % size -Ax app app : section .interp .note.ABI-tag .note.gnu.build-id .gnu.hash
Perhatikan ukuran section .text (0x284) masih sama seperti latihan sebelumnya (Static Link Source Code). Kesimpulan 1. Jika library dilink secara statik dengan main module, alamat fungsi library berada dalam segmen yang sama dengan main module, yaitu code segment. 2. Besarnya ukuran aplikasi ditentukan main module dan library. Tugas Eksplorasi Diskusikan keuntungan dan kerugian library yang dilink secara statik dengan main module di tingkat object code.
Linux System Programming in C
65
Datatrans Informatika
18 Static Link Archive
Tujuan 1. Dapat membuat library yang dilink secara statik di tingkat archive. 2. Memahami keuntungan dan kerugian link statik tingkat archive. Pada latihan sebelumnya, library statistik telah mempunyai fungsi mean untuk menghitung ratarata. Library tersebut akan ditambah fungsi median. Data yang akan dikalkulasi harus disortir terlebih dahulu. Fungsi sortir disajikan dalam source code sort.c yang dikompilasi menjadi object code sort.o. Kali ini terdapat dua object code (stat.o dan sort.o) yang harus dilink dengan main module. Kedua object code dapat diringkas menjadi satu archive bernama libstat.a. Source code disusun dalam layout direktori sebagai berikut:
Gambar 6: Layout Direktori Library dan Main Module Karena library dibuild terpisah dari main module maka memiliki Makefile sendiri. Library di link secara permanen dengan main module ketika aplikasi dibuild.
18.1
Library
18.1.1 Sort File header library adalah sebagai berikut: Listing 60. Header Library — sort.h 1 2 3 4 5 6
% ./app address main 0x400530 address sum dalam library 0x40070c average 3.000000 alamat swap dalam library 0x400863 median 3.00000
Berdasarkan hasil eksekusi, fungsi main, sum dan swap dalam library berada dalam segmen yang sama: % size -Ax app app : section .interp .note.ABI-tag .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .plt .text .fini .rodata .eh_frame_hdr .eh_frame .init_array .fini_array .jcr .dynamic .got .got.plt .data .bss .comment Total
Dibandingkan latihan sebelumnya, perhatikan akibat penambahan fungsi median dan sort terhadap ukuran section .text (0x4c4) yang lebih besar dari pada latihan sebelumnya (0x284). Kesimpulan 1. Jika library dilink secara statik dengan main module, alamat fungsi library berada dalam segmen yang sama dengan main module, yaitu code segment. 2. Besarnya ukuran aplikasi ditentukan main module dan library. Tugas Eksplorasi Diskusikan keuntungan dan kerugian library yang dilink secara statik dengan main module di tingkat archive.
Linux System Programming in C
69
Datatrans Informatika
19 Dynamic Link Shared Object
Tujuan 1. Dapat membuat library yang dilink secara dinamik di tingkat shared object. 2. Memahami keuntungan dan kerugian link dinamik tingkat shared object. Pada latihan sebelumnya, library statistik telah memiliki fungsi mean, median dan sort. Penambahan fungsi mengakibatkan ukuran library makin besar. Karena dilink secara statik dengan main module maka ukuran aplikasi juga makin besar. Layout direktori source code masih sama seperti latihan sebelumnya. Karena library dibuild terpisah dari main module maka memiliki Makefile sendiri. Kali ini library akan dibuild sebagai shared object dan dilink secara dinamik dengan main module. Artinya, library dilink dengan main module bukan ketika build time tetapi ketika run time.
19.1
Library
File header dan definisi library masih sama seperti latihan sebelumnya. Hanya Makefile yang berbeda. Listing 67. Makefile 1 2 3 4 5 6 7 8 9 10
Kali ini ukuran section .text (0x264) lebih kecil dari pada latihan sebelumnya (0x4c4) karena fungsifungsi library tidak dilink secara permanen dengan main module. Mengeksekusinya:
% LD_LIBRARY_PATH=../lib ./app address main 0x400850 address sum dalam library 0x7fc5bda3a81c average 3.000000 alamat swap dalam library 0x7fc5bda3a977 median 3.000000 periksa alokasi memori di /proc/6454/maps selesai memeriksa, ketik sembarang tombol
Sebelum mengetik sembarang tombol untuk mengakhiri proses, mari memeriksa alokasi memori di layar konsol yang lain: % 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
Terlihat di peta memori bahwa main terletak di segmen code (baris 1). Sedangkan fungsi fungsi library terletak dalam segmen memorymapping10 (baris 9). Kesimpulan 1. Jika library dilink secara dinamik dengan main module, alamat fungsi library berada dalam segmen memorymapping.
10 Tentang layout memori lihat di halaman 17. Linux System Programming in C
72
Datatrans Informatika
2. Karena dilink saat run time, ukuran library tidak menyebabkan ukuran aplikasi makin besar. Tugas Eksplorasi Diskusikan keuntungan dan kerugian library yang dilink secara dinamik dengan main module di tingkat shared object.
Linux System Programming in C
73
Datatrans Informatika
VII Library I/O Standard untuk Merekam dan Membaca File
20 Fungsi Library I/O Standard untuk Menyimpan VariableLength Record dalam Format Teks 21 Fungsi Library I/O Standard untuk Membaca Variable Length Record dalam Format Teks 22 Fungsi Library I/O Standard untuk Menyimpan Fixed Length Record dalam Format Teks 23 Fungsi Library I/O Standard untuk Membaca Fixed Length Record dalam Format Teks 24 Fungsi Library I/O Standard untuk Menyimpan Fixed Length Record dalam Format Binary 25 Fungsi Library I/O Standard untuk Membaca Fixed Length Record dalam Format Binary
Linux System Programming in C
74
Datatrans Informatika
20 Fungsi Library I/O Standard untuk Menyimpan VariableLength Record dalam Format Teks
Tujuan Dapat menyimpan variablelength record ke dalam file teks menggunakan fungsi library I/O standard. C menyediakan library I/O standard yang kompatibel untuk bermacammacam sistem operasi. Kita akan berlatih menyimpan dan membaca data ke dalam/dari file teks menggunakan fungsifungsi yang disediakan library tersebut. Untuk sampel, kita menggunakan subjek penyimpanan dan pembacaan data departemen dengan struktur: • Nama Departemen (string) • Headcount (short) • Nama Head Departemen (string)
20.1
Mendeklarasikan Struktur
Terlebih dahulu mari mendefinisikan struktur data departemen. Karena akan disimpan ke dalam file teks maka lebih mudah jika semua elemennya dideklarasikan dengan tipe data string. Listing 70. Deklarasi Struktur Data Departemen — dept_teks.h 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
Record departemen berisi 3 field: name, headcount dan head (nama department head). Tiap record disimpan menjadi baris teks dengan ukuran bervariasi. Fieldfield dipisahkan dengan delimitter TAB. Tiap record diakhiri newline. Berikut ini kode untuk menyimpan data ke dalam file teks. Listing 71. Menyimpan Variablelength Record ke dalam File Teks — job17a.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
Baris 8 sampai 13: deklarasi variabel. Pointer buff menyimpan address alokasi memori di heap. Baris 15: open file dept.txt dalam current directory dengan mode a. Artinya, file dipersiapkan untuk appending (data direkam di akhir file). File dicreate jika tidak eksis. Posisi stream berada di akhir file (end of file). Baris 17: jika gagal membuka file, pesan error ditampilkan di layar komputer. Baris 22 sampai 24: mengclear data departemen sebelum diisi. Baris 28 sampai 36: menerima input dari keyboard dan menyimpannya ke dalam elemen nama departemen. Baris 28 sampai 31: input dari keyboard disimpan dalam buff. Baris 32 dan 33: hapus newline di akhir buff. Baris 34 dan 36: salin string dari buff ke nama departemen, maksimum sebanyak MAX_NAMA_LEN karakter.
Linux System Programming in C
77
Datatrans Informatika
Baris 38 sampai 42: jika pengguna mengetik EXIT maka program diterminate. String di compare secara case insensitive. Baris 46 sampai 68: menerima input dari keyboard dan menyimpannya ke dalam elemen department headcount. Bilangan dibatasi sesuai accepable range yang didefinisikan dalam dept_teks.h: Baris 46 sampai 49: input dari keyboard disimpan dalam buff. Baris 50 dan 51: hapus newline di akhir buff. Baris 52 sampai 55: mengkonversi string dalam buff menjadi integer dan disiman ke dalam count. Baris 56 sampai 62: jika nilai count di luar range maka ulangi input dari keyboard. Baris 63 sampai 67: salin string dari buff ke headcount departemen, maksimum sebanyak MAX_HEADCOUNT_LEN karakter. Baris 71 sampain 80: menerima input dari keyboard dan menyimpannya ke dalam elemen nama department head: Baris 71 sampai 74: input dari keyboard disimpan dalam buff. Baris 75 dan 76: hapus newline di akhir buff. Baris 77 sampai 80: salin string dari buff ke nama departemen head, maksimum sebanyak MAX_HEAD_LEN karakter. Baris 82 sampai 86: merekam record ke dalam file dengan format teks berdelimitter TAB. Baris 89: mengclose file. Baris 90: mendestroy alokasi memori di heap. Mengenerate executable file: %
gcc -o job17a -Wall job17a.c
Mengeksekusinya:
% ./job17a type EXIT to terminate deptartment name: PROD headcount: 200 head name: SLONY type EXIT to terminate deptartment name: FINANCE headcount: 10 head name: BUCARDO type EXIT to terminate deptartment name: exit
Memeriksa file dept.txt: % od -t x1 -c dept.txt 0000000 50 52 4f 44 P R O D 0000020 49 4e 41 4e I N A N 0000040 4f 0a O \n 0000042
09 \t 43 C
32 2 45 E
30 0 09 \t
30 0 31 1
09 \t 30 0
53 S 09 \t
4c L 42 B
4f O 55 U
4e N 43 C
59 Y 41 A
0a \n 52 R
46 F 44 D
Kesimpulan
Linux System Programming in C
78
Datatrans Informatika
1. Jika disimpan dalam format teks, string maupun bilangan disimpan dalam kode ASCII. 2. Pada variablelength record, field harus diakhiri dengan delimitter. 3. Pada variablelength record, record harus diakhiri dengan delimitter. Tugas Eksplorasi Diskusikan keuntungan dan kerugian penyimpanan file teks dengan ukuran record yang variabel.
Linux System Programming in C
79
Datatrans Informatika
21 Fungsi Library I/O Standard untuk Membaca VariableLength Record dalam Format Teks
Tujuan Dapat membaca variablelength record dari file teks menggunakan fungsi library I/O standard. Pada latihan sebelumnya kita sudah mengeksplorasi penyimpanan variablelength record ke dalam file teks. Kali ini kita akan berlatih membaca recordrecord tersebut. Listing 72. Membaca Variablelength Record dari File Teks — job17b.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
Baris 7 sampai 14: mendeklarasikan variabel. Pointer buff berisi alamat alokasi di heap. Baris 16: open file dept.txt dalam current directory dengan mode r. Artinya, file dipersiapkan untuk reading. Posisi stream berada di awal file (beginning of file). Baris 18: jika gagal membuka file, pesan error ditampilkan di layar komputer. Baris 22: membaca isi file teks per baris sehingga mencapai end of file. Baris 23 dan 24: menghilangkan newline di akhir string. Baris 27 dan 28: memparse string dengan delimitter TAB. Baris 31: mengclose file. Baris 32: mendestroy alokasi memori di heap. Mengenerate executable file: %
gcc -o job17b -Wall job17b.c
Mengeksekusinya:
% ./job17b department name: PROD headcount: 200 head name: SLONY department name: FINANCE headcount: 10 head name: BUCARDO
Kesimpulan Tiap baris teks diparse menjadi fieldfield berdasarkan delimitter. Tugas Eksplorasi 1. Bagaimana cara merekonstruksi struktur dept_teks dari tiap baris yang dibaca dari file teks. 2. Bagaimana cara membaca record pada nomor urut tertentu. 3. Dikaitkan dengan latihan sebelumnya tentang penyimpanan variablelength record, bagaimana cara mengupdate dan mendelete suatu record dalam file teks?
Linux System Programming in C
81
Datatrans Informatika
22 Fungsi Library I/O Standard untuk Menyimpan FixedLength Record dalam Format Teks
Tujuan Dapat menyimpan fixedlength record ke dalam file teks menggunakan fungsi library I/O standard.
22.1
Menyimpan Data
Pada latihan sebelumnya, kita sudah mendefinisikan struktur dept_teks11. Record departemen berisi 3 field: name, headcount dan head (nama department head). Tiap record disimpan menjadi baris teks dengan ukuran tetap (fixedlength). Fieldfield tidak perlu dipisahkan dengan delimitter TAB. Tiap record tidak perlu diakhiri newline. Berikut ini kode untuk menyimpan data ke dalam file teks. Listing 73. Menyimpan Fixedlength Record ke dalam File Teks — job17c.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
Penjelasan baris per baris source code sama dengan penyimpanan variablelength record (halaman 76). Hanya berbeda pada baris 55. Record direkam ke dalam file teks tanpa delimitter. Mengenerate executable file: %
gcc -o job17c -Wall job17c.c
Mengeksekusinya:
% ./job17c type EXIT to terminate deptartment name: PROD headcount: 200 head name: SLONY type EXIT to terminate deptartment name: FINANCE headcount: 10 head name: BUCARDO type EXIT to terminate deptartment name: exit
Memeriksa file dept.txt:
% od -t x1 -c dept2.txt 0000000 50 52 4f 44 00 P R O D \0 0000020 00 00 00 00 00
Linux System Programming in C
00 \0 32
00 \0 30
00 \0 30
83
00 \0 00
00 \0 53
00 \0 4c
00 \0 4f
00 \0 4e
00 \0 59
00 \0 00
00 \0 00
Datatrans Informatika
0000040 0000060 0000100 0000120 0000140
\0 00 \0 00 \0 00 \0 00 \0 00 \0
\0 00 \0 00 \0 00 \0 42 B 00 \0
\0 00 \0 00 \0 00 \0 55 U 00 \0
\0 00 \0 00 \0 00 \0 43 C 00 \0
\0 00 \0 00 \0 00 \0 41 A 00 \0
2 00 \0 00 \0 00 \0 52 R 00 \0
0 00 \0 00 \0 00 \0 44 D 00 \0
0 00 \0 00 \0 00 \0 4f O 00 \0
\0 00 \0 46 F 00 \0 00 \0 00 \0
S 00 \0 49 I 00 \0 00 \0 00 \0
L 00 \0 4e N 00 \0 00 \0 00 \0
O 00 \0 41 A 00 \0 00 \0 00 \0
N 00 \0 4e N 00 \0 00 \0 00 \0
Y 00 \0 43 C 31 1 00 \0 00 \0
\0 00 \0 45 E 30 0 00 \0 00 \0
\0 00 \0 00 \0 00 \0 00 \0 00 \0
0000160
Kesimpulan 1. Jika disimpan dalam format teks, string maupun bilangan disimpan dalam kode ASCII. 2. Pada fixedlength record, field tidak diakhiri dengan delimitter. 3. Pada fixedlength record, record tidak diakhiri dengan delimitter. Tugas Eksplorasi Diskusikan keuntungan dan kerugian penyimpanan file teks dengan ukuran record yang fixed.
Linux System Programming in C
84
Datatrans Informatika
23 Fungsi Library I/O Standard untuk Membaca FixedLength Record dalam Format Teks
Tujuan Dapat membaca fixedlength record dari file teks menggunakan fungsi library I/O standard. Pada latihan sebelumnya kita sudah mengeksplorasi penyimpanan fixedlength record ke dalam file teks. Kali ini kita akan berlatih membaca recordrecord tersebut. Listing 74. Membaca Fixedlength Record dari File Teks — job17d.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
Baris 7 dan 8: mendeklarasikan variabel. Baris 10: open file dept.txt dalam current directory dengan mode r. Artinya, file dipersiapkan untuk reading. Posisi stream berada di awal file (beginning of file). Baris 12: jika gagal membuka file, pesan error ditampilkan di layar komputer. Baris 16: membaca isi file teks per ukuran struktur dept_teks sehingga mencapai end of file. Baris 17 sampai 19: menampilkan data departemen. Linux System Programming in C
85
Datatrans Informatika
Baris 22: mengclose file. Mengenerate executable file: %
gcc -o job17d -Wall job17d.c
Mengeksekusinya:
% ./job17b department name: PROD headcount: 200 head name: SLONY department name: FINANCE headcount: 10 head name: BUCARDO
Kesimpulan Membaca fixedlength record dari file teks lebih sederhana dibandingkan variablelength record. Tugas Eksplorasi 1. Bagaimana cara membaca record pada nomor urut tertentu? 2. Dikaitkan dengan latihan sebelumnya tentang menyimpan fixedlength record, bagaimana cara mengupdate dan mendelete suatu record dalam file teks? 3. Diskusikan keuntungan dan kerugian penyimpanan file teks dengan ukuran record yang fixed.
Linux System Programming in C
86
Datatrans Informatika
24 Fungsi Library I/O Standard untuk Menyimpan FixedLength Record dalam Format Binary
Tujuan Dapat menyimpan fixedlength record ke dalam file binary menggunakan fungsi library I/O standard.
24.1
Mendeklarasikan Struktur
Terlebih dahulu mari mendefinisikan struktur data departemen. Listing 75. Deklarasi Struktur Data Departemen — dept_bin.h 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
Penjelasan baris per baris source code sama dengan penyimpanan fixedlength record ke dalam file teks (halaman 82). Hanya berbeda pada barisbaris berikut ini: • Baris 15: open file dept.dat menggunakan mode ab. Mode a berati file dipersiapkan untuk appending (data direkam di akhir file). File dicreate jika tidak eksis. Posisi stream berada di akhir file (end of file). Mode b menunjukkan tipe file binary. • Baris 45: headcount bertipe bilangan bulat. • Baris 55: record direkam ke dalam file teks tanpa delimitter. Linux System Programming in C
88
Datatrans Informatika
Mengenerate executable file: %
gcc -o job17e -Wall job17e.c
Mengeksekusinya:
% ./job17e type EXIT to terminate deptartment name: PROD headcount: 200 head name: SLONY type EXIT to terminate deptartment name: FINANCE headcount: 10 head name: BUCARDO type EXIT to terminate deptartment name: exit
Memeriksa file dept.dat: % od -t x1 -c dept.dat 0000000 50 52 4f 44 P R O D 0000020 00 00 00 00 \0 \0 \0 \0 0000040 00 00 00 00 \0 \0 \0 \0 0000060 00 00 00 00 \0 \0 \0 \0 0000100 00 00 00 00 \0 \0 \0 \0 0000120 42 55 43 41 B U C A 0000140 00 00 00 00 \0 \0 \0 \0 0000160
Perhatikan struktur data dept_bin terekam dalam file binary. • Elemen nama dicetak merah sebanyak 22 byte (21 byte plus 1 byte padding). • Elemen headcount dicetak biru. • Elemen head dicetak hijau (31 bytes plus 1 byte padding). Kesimpulan 1. Jika disimpan dalam format binary, data disimpan sesuai representasi binernya. 2. Harus memperhatikan byte alignment ketika direkam atau dibaca pada sistem oeprasi yang berbeda. 3. Pada fixedlength record, field tidak diakhiri dengan delimitter. 4. Pada fixedlength record, record tidak diakhiri dengan delimitter. Tugas Eksplorasi 1. Bagaimana cara mengupdate suatu record dalam file binary dengan ukuran record yang fixed? 2. Bagaimana cara mendelete suatu record dalam file binary dengan ukuran record yang fixed? 3. Diskusikan keuntungan dan kerugian penyimpanan file binary dibandingkan file teks.
Linux System Programming in C
89
Datatrans Informatika
25 Fungsi Library I/O Standard untuk Membaca FixedLength Record dalam Format Binary
Tujuan Dapat membaca fixedlength record dari file binary menggunakan fungsi library I/O standard. Pada latihan sebelumnya kita sudah mengeksplorasi penyimpanan fixedlength record ke dalam file binary. Kali ini kita akan berlatih membaca recordrecord tersebut. Listing 77. Membaca Fixedlength Record dari File Binary — job17f.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
Penjelasan baris per baris source code sama dengan pembacaan fixedlength record (halaman 85). Hanya berbeda pada barisbaris berikut ini: • Baris 10: open file dept.dat menggunakan mode rb. Mode r berarti file dipersiapkan untuk reading. Posisi stream berada di awal file (beginning of file). Mode b menunjukkan tipe file binary. • Baris 16: membaca isi file binary per ukuran struktur dept_bin sehingga mencapai end of file. Linux System Programming in C
90
Datatrans Informatika
• Baris 18: format printf menggunakan placeholder %d untuk headcount bertipe bilangan bulat. Mengenerate executable file: %
gcc -o job17e -Wall job17e.c
Mengeksekusinya:
% ./job17e department name: PROD headcount: 200 head name: SLONY department name: FINANCE headcount: 10 head name: BUCARDO
Kesimpulan Jika file direkam pada sistem operasi yang berbeda maka byte alignment harus diperhatikan. Tugas Eksplorasi 1. Diskusikan keuntungan dan kerugian penyimpanan file binary dibandingkan file teks. 2. Bagaimana cara mengupdate suatu record dalam file binary dengan ukuran record yang fixed? 3. Bagaimana cara mendelete suatu record dalam file binary dengan ukuran record yang fixed?
Linux System Programming in C
91
Datatrans Informatika
VIII Library I/O Low Level untuk Merekam dan Membaca File
26 Fungsi Library I/O Low Level untuk Menyimpan Fixed Length Record dalam Format Binary 27 Fungsi Library I/O Low Level untuk Membaca Fixed Length Record dalam Format Binary 28 Vector Write untuk Menyimpan FixedLength Record 29 Vector Read untuk Membaca FixedLength Record
Linux System Programming in C
92
Datatrans Informatika
26 Fungsi Library I/O Low Level untuk Menyimpan FixedLength Record dalam Format Binary
Tujuan Dapat menyimpan fixedlength record ke dalam file binary menggunakan fungsi library I/O low level. Pada latihan sebelumnya kita menggunakan library I/O standard untuk menyimpan dan membaca data ke/dari file. Kali ini kita akan berlatih menggunakan library I/O low level yang disediakan Linux. Library I/O standard diimplementasikan di atas library I/O low level. Sehingga akan lebih efisien jika menggunakan library I/O level secara langsung. Untuk tema latihan, kita menggunakan struktur dept_bin yang telah dijelaskan di halaman 87. Listing 78. Menyimpan Record ke dalam File Binary — job17g.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
% ./job17e type EXIT to terminate deptartment name: PROD headcount: 200 head name: SLONY type EXIT to terminate deptartment name: FINANCE headcount: 10 head name: BUCARDO type EXIT to terminate deptartment name: exit
Baris 19: open file dept2.dat dengan flags O_CREAT|O_WRONLY|O_APPEND. Artinya, file tersebut dicreate jika tidak eksis (O_CREAT), hanya untuk menyimpan data tanpa membacanya (O_WRONLY) dan data disimpan di posisi akhir file (O_APPEND).
Linux System Programming in C
94
Datatrans Informatika
File tersebut diopen dengan permission mode: S_IRUSR|S_IWUSR. Artinya, hanya dapat dibaca dan diubah oleh user pemilik file: % ls dept2.dat -l -rw------- 1 abdul abdul 112 Oct 16 22:37 dept2.dat
Kesimpulan Berbeda dengan library I/O standard, library I/O low level tidak menggunakan pointer FILE* sebagai penanda. Tetapi menggunakan bilangan bulat file descriptor.
Linux System Programming in C
95
Datatrans Informatika
27 Fungsi Library I/O Level untuk Membaca FixedLength Record dalam Format Binary
Tujuan Dapat membaca fixedlength record dari file binary menggunakan fungsi library I/O low level. Pada latihan sebelumnya kita sudah mengeksplorasi penyimpanan fixedlength record ke dalam file binary menggunakan library I/O level. Kali ini kita akan berlatih membaca record record tersebut. Listing 79. Membaca Fixedlength Record dari File Binary — job17h.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
% ./job17h department name: PROD headcount: 200 head: SLONY department name: FINANCE headcount: 10 head: BUCARDO
Kesimpulan Berbeda dengan library I/O standard, library I/O low level tidak menggunakan pointer FILE* sebagai penanda. Tetapi menggunakan bilangan bulat file descriptor. Tugas Eksplorasi 1. Bagaimana cara mengupdate suatu record dalam file binary dengan ukuran record yang fixed menggunakan library I/O low level? 2. Bagaimana cara mendelete suatu record dalam file binary dengan ukuran record yang fixed menggunakan library I/O low level?
Linux System Programming in C
97
Datatrans Informatika
28 Vector Write untuk Menyimpan Fixed Length Record
Tujuan Dapat menyimpan beberapa fixedlength record menggunakan vector write ke dalam file binary. Untuk merekam data ke dalam file, kita menggunakan fungsi write dengan mengirimkan argumen alamat buffer data dan banyaknya byte. Selanjutnya, fungsi write merekam data dari memori yang contiguous ke dalam file. Untuk merekam beberapa data yang tersebar di beberapa alamat memori, kita mempunyai 2 pilihan. Pertama, membuat array baru dan menyalin datadata tersebut ke dalamnya. Kedua, memanggil perintah write berulangulang untuk setiap item data. Keduanya tidak efisien. Library I/O level menyediakan fungsi writev (vector write) yang dapat merekam sekaligus datadata yang tersebar di alamat memori.
28.1
Satu Perusahaan dan Beberapa Departemen
Pada latihan sebelumnya kita telah memiliki struktur dept_bin. Kali ini kita akan membuat struktur baru: company. Listing 80. Struktur Company — company.h 1 2 3 4 5 6 7 8 9 10 11 12
Kasus: perusahaan PT. ABC beralamat di Batam memiliki 2 departemen: PROD dan FINANCE. Data akan direkam ke dalam file dengan susunan sebagai berikut: • Perusahaan: PT. ABC, struktur data: company. • Departemen: PROD, struktur data: dept_bin. • Departemen: FINANCE, struktur data: dept_bin.
Linux System Programming in C
98
Datatrans Informatika
Karena tipe data departemen PROD dan FINANCE sama maka dapat disusun ke dalam sebuah array berada dalam satu area memori contiguous. Namun, tipe data perusahaan PT. ABC berbeda sehingga ditempatkan di area memori terpisah.
28.2
Vector Write
Jika menggunakan fungsi write maka kita akan merekam data dua kali ke dalam sebuah file. Pertama untuk perusahaan PT. ABC. Kedua untuk array berisi departemen PROD dan FINANCE. Menggunakan vector write, kita mengerjakannya secara lebih efisien: hanya satu kali perekaman. Listing 81. Merekam Data Menggunakan Vector Write — job17i.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
Baris 19: deklarasi variabel c bertipe struktur company. Baris 20: deklarasi array d berisi 2 elemen bertipe struktur dept_bin. Baris 23: mengisi data perusahaan. Baris 24 dan 25: mengisi data dua departemen. Baris 27 sampai 30: mendaftarkan perusahaan dan kedua departemen ke dalam structure iovec. Perhatikan bahwa kita hanya mencatat alamat data ke dalam structure iovec, bukan menyalin data. Baris 32: membuka file dept3.dat untuk creating (isi file lama ditruncate). Posisi stream berada di awal file (beginning of file) Baris 38: memanggil fungsi vector write. Baris 40: mengclose file. Mengenerate executable file: %
gcc -o job17i -Wall job17i.c
Mengeksekusinya: %
./job17i
Memeriksa file dept3.dat: % od -t x1 -c dept3.dat 0000000 50 54 2e 20 P T . 0000020 00 00 00 00 \0 \0 \0 \0 0000040 00 00 00 00 \0 \0 \0 \0 0000060 00 00 00 00 \0 \0 \0 \0 0000100 4f 44 00 00 O D \0 \0 0000120 59 00 00 00 Y \0 \0 \0 0000140 00 00 46 49 \0 \0 F I 0000160 42 55 43 41 B U C A 0000200 00 00 00 00 \0 \0 \0 \0 0000206
41 A 00 \0 00 \0 00 \0 00 \0 00 \0 4e N 52 R 00 \0
Warna merah adalah rekaman data perusahaan PT. ABC. Warna biru adalah rekaman data departemen PROD. Warna hijau adalah rekaman data departemen FINANCE. Kesimpulan
Linux System Programming in C
100
Datatrans Informatika
Vector write dapat merekam sekaligus beberapa data yang teretak di area memori yang tidak contiguous ke dalam file. Tugas Eksplorasi 1. Diskusikan keuntungan vector write? 2. Buatlah program untuk merekam purchase order berisi sebuah header dan beberapa item order ke dalam sebuah file binary.
Linux System Programming in C
101
Datatrans Informatika
29 Vector Read untuk Membaca Fixed Length Record
Tujuan Dapat membaca beberapa fixedlength record dari file binary menggunakan vector read. Pada latihan sebelumnya kita sudah mengeksplorasi vector write untuk menyimpan sekaligus beberapa data yang berada di alamat memori yang tidak contiguous. Kali ini kita akan berlatih membaca record dari file binary menggunakan read vector. Record record yang dibaca dari file ditempatkan di lokasilokasi memori yang tidak contiguous: • Sebuah data perusahaan bertipe struktur company. • Sebuah array berisi 2 elemen bertipe struktur dept_bin. Listing 82. Membaca Data Menggunakan Vector Read — job17j.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
% ./job17j company name: PT. ABC comapny address: BATAM department name: PROD headcount: 200 head name: SLONY department name: FINANCE headcount: 10 head name: BUCARDO
Perhatikan, kita berhasil membaca data dari file sekaligus untuk struktur data company (warna merah) dan array berisi 2 struktur data dept_bin (warna biru). Kesimpulan Vector read dapat membaca sekaligus beberapa data dari file dan menyimpannya di lokasi lokasi memori yang tidak contiguous. Tugas Eksplorasi 1. Diskusikan keuntungan vector read? 2. Buatlah program untuk membaca data purchase order berisi sebuah header dan beberapa item order dari sebuah file binary.
Linux System Programming in C
103
Datatrans Informatika
IX Komunikasi Via USB to parallel Port Converter
30 Simulasi parallel Port Menggunakan USB to Parallel Port Converter
Linux System Programming in C
104
Datatrans Informatika
30 Simulasi parallel Port Menggunakan USB to Parallel Port Converter
Tujuan Dapat mengirim data secara paralel ke piranti eksternal melalui USB to parallel port converter. Saat ini jarang komputer dilengkapi parallel port. Namun demikian kita dapat menggunakan USB to parallel port converter untuk mengirim data ke piranti eksternal. Umumnya converter yang dijual di pasar adalah untuk dihubungkan dengan printer. Kita tidak dapat langsung menggunakannya untuk eksperimen. Salah satu artikel yang menarik adalah : http://www.http://thx8411.over blog.com/pages/Add_TTL_outputs_to_your_USB_Laptop_Part_1_Hardware3229030.html. Sirkuit elektronika yang dijelaskan dalam dokumen tersebut harus dimodifikasi sebagai berikut:
Gambar 7: Modifikasi Sirkuit Eksperimen USB to parallel Converter
30.1
Menghubungkan Piranti Eksternal dengan DB25 Converter
Linux System Programming in C
105
Datatrans Informatika
Gambar 8: Piranti Eksternal dan Converter Hubungkan piranti eksternal ke converter.
Gambar 9: Piranti Eksternal Terhubung ke Converter
30.2
Memeriksa Registrasi Driver
Ketik konektor converter ditancapkan ke saluran USB, pastikan driver telah diregistrasi oleh Linux: % dmesg [ 7269.348197] usb 6-1: new full-speed USB device number 2 using uhci_hcd [ 7269.527243] usb 6-1: New USB device found, idVendor=067b, idProduct=2305 [ 7269.527251] usb 6-1: New USB device strings: Mfr=1, Product=2, SerialNumber=0 [ 7269.527256] usb 6-1: Product: IEEE-1284 Controller [ 7269.527261] usb 6-1: Manufacturer: Prolific Technology Inc. [ 7269.631290] usblp 6-1:1.0: usblp0: USB Bidirectional printer dev 2 if 0 alt 1 proto 2 vid 0x067B pid 0x2305 [ 7269.631340] usbcore: registered new interface driver usblp
30.3
Menemukan Path
Berikutnya adalah menemukan path untuk mengopen converter. % ls /dev/usb lp0
Linux System Programming in C
106
Datatrans Informatika
Jadi, converter diakses melalui path /dev/usb/lp012.
30.4
Source Code
Listing 83. Mengirim Byte Data ke LED Paralel — job18a.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
#include #include #include #include #include
<stdio.h> <sys/types.h> <sys/stat.h>
int main() { int i, fd; fd=open("/dev/usb/lp0",O_WRONLY); if(fd<0) { perror("usblp0"); return 1; } char d=0b10000000; for(i=0; i<8; i++){ write(fd, &d, 1); d = d>>1; sleep(1); } close(fd); return 0; }
Mengenerate executable file: %
gcc -o job18a -Wall job18a.c
Mengeksekusinya: %
sudo ./job18a
Tugas Eksplorasi Kembangkan kreativitas untuk mengatur nyala lampu secara dekoratif.
12 Dapat juga berada di path lain, misalnya /dev/usblp0. Linux System Programming in C
107
Datatrans Informatika
X Komunikasi Via USB to Serial Port Converter
31 Mempersiapkan Inter Koneksi Serial Port dan Library 32 Mengirim dan Menerima Baris String 33 Menggunakan Vector Write untuk Mengirim Data
Linux System Programming in C
108
Datatrans Informatika
31 Mempersiapkan Inter Koneksi Serial Port dan Library
Tujuan 1. Mempersiapkan inter koneksi antar serial port. 2. Mempersiapkan library untuk inisialisasi serial port.
31.1
Inter Koneksi
Sebagaimana parallel port, komputer saat ini jarang dilengkapi serial port. Untuk mensimulasikan komunikasi via serial port, kita akan menggunakan USB to serial port converter. Untuk berkomunikasi, konektor DB9 antara 2 converter dihubungkan melalui saluran full handshaking null modem:
Gambar 10: Full Handshaking Null Modem
31.2
Library
Kita akan membuat library statik untuk menginisialisasi serial port. Library ini akan dipergunakan dalam tugastugas berikutnya. Listing 84. Header — serial.h 1 2 3 4 5 6
#ifndef _SERIAL_H_ #define _SERIAL_H_ extern int serialport(const char* path); #endif
tty.c_cc[VTIME]=0;//time to wait for data (tenths of seconds) tty.c_cc[VMIN]=255;//minimum number of characters to read cfmakeraw(&tty); //terminal raw mode, 8 data bits, no parity if(tcflush(fd, TCIOFLUSH)==-1) { perror("serial_parameter, i/o flush"); return 0; } if(tcsetattr ( fd, TCSANOW, &tty )==-1){ perror("serial_paraneter, set attribute"); return 0; } printf("set serial parameter ok\n"); return 1; }
Baris 1: atur path sesuai lokasi library. Mengenerate executable file: %
make
Kita memperoleh 2 executable file: sendline dan recvline.
32.4
Eksekusi
Di terminal komputer penerima, login sebagai root, ketik command line berikut ini: %
./recvline /dev/ttyUSB0
Di terminal komputer pengirim, login sebagai root, ketik command line berikut ini: %
./sendline /dev/ttyUSB0
Jika perlu, ubah /dev/ttyUSB0 sesuai access path serial port komputer anda. Tugas Eksplorasi Buatlah program chatting antar 2 komputer melalui serial port. Baik program pengirim maupun penerima diterminate jika salah satu pengguna mengirim string EXIT.
Linux System Programming in C
114
Datatrans Informatika
33 Menggunakan Vector Write untuk Mengirim Data
Tujuan Dapat mengirim data antar komputer melalui serial port menggunakan vector write. Pada latihan tentang merekam file, kita telah mengeksplorasi penggunaan vector write untuk merekam data yang tersebar di area memori yang tidak contiguous ke dalam file. Kali ini kita mencoba memanfaatkannya untuk mengirim data via serial port.
Baris 1: atur path sesuai lokasi library. Mengenerate executable file: %
make
Kita memperoleh 2 executable file: sendstr dan recvstr.
33.4
Eksekusi
Di terminal komputer penerima, login sebagai root, ketik command line berikut ini: %
./recvstr /dev/ttyUSB0
Di terminal komputer pengirim, login sebagai root, ketik command line berikut ini: %
./sendstr /dev/ttyUSB0
Jika perlu, ubah /dev/ttyUSB0 sesuai access path serial port komputer anda. Tugas Eksplorasi Buatlah program untuk mengirim file antar komputer via serial port.
Linux System Programming in C
118
Datatrans Informatika
XI Multithread
34 Multithread dan Efisiensi 35 Race Condition 36 Mutex untuk Singkronisasi Akses Memori 37 Mutex untuk Singkronisasi Akses Piranti I/O 38 Mutex untuk Chat Via Serial Port 39 Loop yang Tidak Efisien 40 Condition Variable 41 Semaphore 42 Thread Pool
Linux System Programming in C
119
Datatrans Informatika
34 Multi Thread dan Efisiensi
Tujuan 1. Memahami masalah efisiensi pada program single thread. 2. Dapat membuat program multi thread untuk eksekusi lebih cepat.
34.1
Single Thread dan Masalah Efisiensi
Thread adalah single sequential flow of control di dalam suatu program. Pada latihanlatihan terdahulu kita sudah membuat programprogram berisi thread tunggal, disebut main thread. Berikut ini adalah program dengan thread tunggal. Listing 93. Single Thread — job19a.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
Baris 11: mencatat detik awal sebelum loop. Baris 13: loop untuk simulasi kesibukan processor. Baris 15: mencatat detik akhir setelah loop. Baris 16: menampilkan banyaknya pengulangan. Baris 17: menampilkan waktu eksekusi processor. Mengenerate executable file: %
gcc -o job19a -Wall job19a.c
Terlebih dahulu aktifkan System Monitor untuk memantau beban processor. Lalu mengeksekusi job19a: Linux System Programming in C
120
Datatrans Informatika
% ./job19a count 2000000000 waktu eksekusi 7 detik
Mari melihat grafik beban processor menggunakan System Monitor:
Gambar 11: Beban Processor pada Program Single Thread Selama eksekusi job19a, CPU1 dibebani 100% sedangkan CPU2 kurang dari 50%. Hanya CPU1 yang sangat sibuk karena program hanya menggunakan single thread.
34.2
Multi Thread
Jika kedua CPU dibebani secara berimbang, eksekusi program akan lebih cepat. Kita membagi loop secara imbang untuk kedua processor. Program berikut ini memiliki 3 thread: • Main thread: thread utama yang mengcreate 2 thread berikutnya. • Subthread untuk loop pertama. • Subthread untuk loop kedua. Listing 94. Multi Thread — job19b.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
Baris 2: deklarasi callback function yang akan dieksekusi dalam subthread. Baris 18: deklarasi variabel attr bertipe struktur pthread_attr_t adalah atribut untuk meng create thread. Baris 19: deklarasi variabel status0 dan status1 untuk menyimpan status create subthread. Baris 20: deklarasi variabel param bertipe struktur sched_param. Variabel ini adalah parameter untuk mengatur prioritas jadwal subthread. Baris 22: menginisialisasi attr. Elemenelemen atribut diisi nilai default. Setelah selesai, atribut ini harus didestroy (baris 49). Baris 23: mengatur atribut agar subthread berstatus joinable ketika selesai melaksanakan tugas. Dengan demikian, main thread dapat memastikan suatu subthread selesai sebelum melanjutkan eksekusi kode berikutnya. Baris 25 sampai 27: jadwal subthread diatur dengan prioritas 0 dan policy SCHED_OTHER. Dua subthread yang akan dicreate mempunyai prioritas sama. Baris 29: mencatat waktu sebelum looping. Baris 31 sampai 36: mengcreate 2 subthread. Jika gagal maka status bernilai selain 0. Fungsi pthread_create membutuhkan 4 argumen: • Argumen output: pointer untuk menyimpan thread id (&thd0 dan &thd1). • Argumen input: pointer atribut subthread (&attr). • Argumen input: callback function yang akan dieksekusi dalam subthread (myloop). Linux System Programming in C
122
Datatrans Informatika
• Argumen input: pointer argumen yang akan dikirimkan bagi callback function ((void*)&arg1 dan (void*)&arg2). Baris 38 sampai 41: menanti subthread selesai dan menerima data dari subthread menggunakan pointer count0 dan count1. Baris 43: mencatat waktu setelah looping. Baris 44: menampilkan banyaknya loop yang telah dikerjakan masingmasing subthread. Baris 45: menampilkan waktu eksekusi processor. Baris 47 dan 48: memfree memori variabelvariabel yang dialokasikan di heap di dalam subthread (baris 61). Baris 49: mendestroy atribut subthread. Baris 54 sampai 65: definisi callback function yang dieksekusi dalam subthread. Baris 55: deklarasi variabel i untuk kendali loop. Baris 56: inisialisasi pointer pMax yang menerima casting argumen input dari tipe void* menjadi int*. Baris 57: deklarasi pointer pRet yang dipersiapkan untuk mengirim nilai bagi main thread ketika subthread berakhir. Baris 59: loop untuk simulasi kesibukan processor. Baris 61: mengalokasikan memori di heap untuk menyimpan data bertipe integer yang akan dikirimkan bagi main thread. Alokasi di heap mencegah variabel didestroy ketika subthread berakhir. Selanjutnya, tugas main thread untuk mendestroynya dari heap (baris 47 dan 48). Baris 62: menyimpan nilai kendali loop i ke alokasi memori di heap. Baris 64: mengakhiri subthread dan mereturn data bagi main thread. Mengenerate executable file: %
gcc -o job19b -Wall job19b.c -lpthread
Terlebih dahulu aktifkan System Monitor untuk memantau beban processor. Lalu mengeksekusi job19b: % ./job19b count0 1000000000 count 1 1000000000 waktu eksekusi 3 detik
Dibandingkan single thread, program versi multi thread menyelesaikan tugas 2 kali lebih cepat. Beban processor dibagi secara imbang untuk kedua processor:
Gambar 12: Beban Processor pada Program Multi Thread Kesimpulan
Linux System Programming in C
123
Datatrans Informatika
1. Multi thread dapat mengeksekusi beberapa sequence kode secara paralel dalam sebuah program. 2. Multi thread dapat mempercepat eksekusi program. Tugas Eksplorasi 1. Ubahlah program sehingga mempunyai 5 thread: 1 main thread dan 4 thread untuk menyelesaikan loop. Apakah menjadi lebih cepat? 2. Berapa batas maksimum banyaknya thread di dalam sebuah program?
Linux System Programming in C
124
Datatrans Informatika
35 Race Condition
Tujuan Memahami efek race condition pada program multi thread. Race condition terjadi ketika lebih dari satu thread mengubah nilai variabel di area memori yang sama. Kejadian ini mengakibatkan nilai variabel tersebut tidak konsisten. Mari membuktikannya. Listing 95. Race Condition — job19c.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
Baris 6 sampai 9: deklarasi struktur thdarg yang akan digunakan sebagai argumen bagi subthread. Baris 20: field maxloop diisi setengah MAXLOOP. Kita akan membagi dua beban loop bagi 2 subthread. Baris 21: field number diset 0. Field inilah yang akan dijadikan target race condition. Baris 54: nilai field number diincrement. Kita akan melihat efek race condition. Mengenerate executable file: %
gcc -o job19c -Wall job19c.c -lpthread
Mengeksekusinya berkalikali menghasilkan nilai yang tidak konsisten dan tidak tepat (seharusnya 100000000): % ./job19c number 73559334 % ./job19c number 67883887 % ./job19c number 77807591
Kesimpulan 1. Race condition terjadi ketika lebih dari satu thread mengubah nilai variabel di area memori yang sama. 2. Race condition menyebabkan nilai variabel tidak konsisten. 3. Dibutuhkan metode singkronisasi untuk menangani race condition.
Linux System Programming in C
126
Datatrans Informatika
36 Mutex untuk Singkronisasi Akses Memori
Tujuan Dapat membuat program menggunakan metode singkronisasi mutex untuk menangani race condition akses area memori pada program multi thread. Pada latihan berikut ini kita akan menggunakan metode singkronisasi mutex (mutual exclusion) untuk menangani race condition dalam mengakses area memori pada program multi thread. Berikut ini adalah revisi source code race condition13. Listing 96. Pengantar Mutex — job19d.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
Berikut ini penjelasan hanya untuk barisbaris revisi source code race condition14. Baris 8: field number dalam struktur thdarg adalah area memori yang akan menjadi target race condition. Baris 9: menambahkan elemen mtx bertipe union pthread_mutex_t. Baris 20: mendeklarasikan variabel mtx_attr bertipe union pthread_mutexattr_t. Ini adalah atribut untuk menginisialisasi mutex mtx. Baris 25: menginisialisasi mtx_attr. Di akhir program, atribut ini harus didestroy (baris 50). Baris 26: mengatur ruang ingkup mtx agar hanya dapat diakes di dalam proses yang tengah berlangsung (tidak dishared dengan prosesproses lain). Baris 27: menginisialisasi mtx sesuai atribut mtx_attr. Di akhir program, mtx ini harus di destroy (baris 51). Baris 50: mendestroy atribute mtx_attr. Baris 51: mendestroy mtx.
14 Untuk penjelasan baris-baris lain, lihat halaman 125. Linux System Programming in C
128
Datatrans Informatika
Baris 62: singkronisasi dengan cara melock mtx. Setiap saat hanya ada satu thread yang dapat melock mutex mtx. Thread lainnya menanti thread pemenang mengunlock mtx tersebut (baris 64). Dengan demikian, dapat dipastikan variabel number (baris 63) diakses hanya oleh sebuah thread setiap saat. Baris 64: mutex mtx diunlock agar thread lain yang menanti giliran dapat melocknya. Mengenerate executable file: %
gcc -o job19d -Wall job19d.c -lpthread
Mengeksekusinya berkalikali menghasilkan nilai yang konsisten dan tepat 100000000: % ./job19d number 100000000 % ./job19d number 100000000 % ./job19d number 100000000
Kesimpulan Metode singkronisasi mutex menangani race condition dengan cara memproteksi suatu area memori agar setiap saat hanya dapat diakses oleh sebuah thread.
Linux System Programming in C
129
Datatrans Informatika
37 Mutex untuk Singkronisasi Akses Piranti I/O
Tujuan Dapat membuat program menggunakan metode singkronisasi mutex untuk menangani race condition akses perangkat I/O pada program multi thread. Pada latihan sebelumnya kita telah membahas pemrograman perangkat I/O dan penggunaan metode singkronisasi mutex untuk akses memori. Kali ini kita akan menerapkan mutex untuk singkronisasi akses perangkat I/O. Piranti I/O yang akan digunakan adalah deretan lampu LED dan USB to parallel converter15. Diumpamakan ada sebuah pabrik memiliki 2 stasiun produksi beroperasi paralel: • Stasiun 1 membutuhkan setup time 5 detik dan cycle time 3 detik. • Stasiun 2 membutuhkan setup time 6 detik dan cycle time 2 detik. Buatlah program multi thread untuk mensimulasikan operasi pabrik untuk menyelesaikan n unit produk. Progres pengerjaan produk ditampilkan berupa kombinasi nyala lampu deretan LED yang terhubung ke komputer melalui konverter USB to parallel port. Listing 97. Simulasi Pabrik — job19e.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
Yang perlu diperhatikan adalah kode pada baris 118 sampai 124. Ada 3 objek yang diproteksi menggunakan mutex: • Area memori: maxqty. • Area memori: runqty. • Sumber daya I/O: fd. Mengenerate executable file: Linux System Programming in C
132
Datatrans Informatika
%
gcc -o job19e -Wall job19e.c -lpthread
Mengeksekusinya: dengan privilege root, ketik command line: % ./job19d /dev/usb/lp0 20 station 2 memulai setup station 1 memulai setup station 1 memulai produksi station 2 memulai produksi station 1 menyelesaikan total 1 unit station 2 menyelesaikan total 1 unit station 2 menyelesaikan total 2 unit station 1 menyelesaikan total 2 unit station 2 menyelesaikan total 3 unit station 1 menyelesaikan total 3 unit station 2 menyelesaikan total 4 unit station 2 menyelesaikan total 5 unit station 1 menyelesaikan total 4 unit station 2 menyelesaikan total 6 unit station 1 menyelesaikan total 5 unit station 2 menyelesaikan total 7 unit station 2 menyelesaikan total 8 unit station 1 menyelesaikan total 6 unit station 2 menyelesaikan total 9 unit station 1 menyelesaikan total 7 unit station 2 menyelesaikan total 10 unit station 2 menyelesaikan total 11 unit station 1 menyelesaikan total 8 unit station 1 selesai produksi station 2 menyelesaikan total 12 unit station 2 selesai produksi stat: 1 menyelesaikan total 8 unit stat: 2 menyelesaikan total 12 unit
Perhatikan bahwa stasiun 2 menyelesaikan lebih banyak unit dibandingkan stasiun 1 karena cycle time yang lebih cepat. Kesimpulan Sebagaimana area memori, akses terhadap sumber daya I/O dalam program multi thread juga harus disingkronisasi. Tugas Eksplorasi Bagaimana jika pabrik tersebut harus memproses unit prodek dalam 2 fase. Fase pertama dikerjakan secara paralel oleh stasiun 1 dan 2 (seperti yang telah kita bahas). Setelah seluruh unit selesai, dilanjutkan fase kedua terdiri atas stasiunstasiun paralel: 3 dan 4.
Linux System Programming in C
133
Datatrans Informatika
38 Mutex untuk Chat Via Serial Port
Tujuan Dapat menerapkan mutex untuk singkronisasi read dan write serial port dalam program multi thread. Pada latihan sebelumnya kita telah mengembangkan aplikasi chat via serial port16. Dengan menerapkan pemrograman multi thread, kita akan mengimprove aplikasi tersebut sehingga dapat mengirim dan menerima pesan secara bersamaan.
38.1
Library
Terlebih dahulu mari membuat library untuk inisialisasi serial port agar beroperasi secara asingkron. Buatlah direkori khusus untuk filefile serial.h, serial.c dan Makefile berikut ini. Listing 98. Header — serial.h 1 2 3 4 5 6
#ifndef _SERIAL_H_ #define _SERIAL_H_ extern int serialport(const char* path); #endif
static int set_param(int fd); int serialport(const char* path) { int fd=-1, ok=0, flag; while(1) { fd=open(path, O_RDWR|O_NOCTTY|O_NDELAY|O_NONBLOCK); if(fd==-1) { perror(path); break; } fcntl(fd, F_SETOWN, getpid());//allow the process to receive SIGIO
21
flag=fcntl(fd, F_GETFL, 0);
16 Lihat halaman 114. Linux System Programming in C
flag|=FASYNC; fcntl(fd, F_SETFL, flag);//make the file descriptor asynchronous if( !set_param(fd) ) { break; } ok=1; break; } if(!ok && fd!=-1){ close(fd); fd=-1; } return fd; } static int set_param(int fd) { struct termios tty; memset(&tty, 0, sizeof(tty)); if ( tcgetattr (fd, &tty) != 0 ){ perror("serial_parameter, get attr"); return 0; } cfsetospeed(&tty, (speed_t)B115200); cfsetispeed(&tty, (speed_t)B115200); tty.c_cflag &= ~CSTOPB;//one stop bit tty.c_cflag |= CRTSCTS; //flow control CTS RTS tty.c_cflag |= CREAD;//enable receiver tty.c_cflag |= CLOCAL;//ignore Carrier Detect tty.c_cc[VTIME]=0;//time to wait for data (tenths of seconds) tty.c_cc[VMIN]=255;//minimum number of characters to read cfmakeraw(&tty); //terminal raw mode, 8 data bits, no parity if(tcflush(fd, TCIOFLUSH)==-1) { perror("serial_parameter, i/o flush"); return 0; } if(tcsetattr ( fd, TCSANOW, &tty )==-1){ perror("serial_paraneter, set attribute"); return 0; } printf("set serial parameter ok\n"); return 1; }
Inisialisasi serial port agar beroperasi secara asingkron dikerjakan pada barisbaris berikut ini. Baris 14: flag O_NONBLOCK dalam open serial port . Barsi 20 sampai 23: status flag serial port dipersiapkan untuk operasi asingkron. Listing 100. Makefile 1
Baris 1: atur SERIALPATH sesuai direktori library serial port di komputer anda. Mengenerate aplikasi: %
make
Mengeksekusi aplikasi dengan privilege root: %
./chat /dev/ttyUSB0 myname
Sesuaikan /dev/ttyUSB0 dengan access path serial port komputer anda. Ubah myname sesuai nama anda. Kesimpulan Dalam aplikasi chat menggunakan multi thread, pengiriman dan penerimaan pesan dapat dilakukan secara bersamaan.
Linux System Programming in C
139
Datatrans Informatika
39 Loop yang Tidak Efisien
Tujuan Memahami ketidakefisienan loop dalam singkronisasi program multi thread. Sebuah pabrik memiliki 2 stasiun: produksi dan packing. Statsiun produksi membutuhkan waktu 2 detik untuk memproses setiap unit produk. Sedangkan packing membutuhkan waktu 1 detik per unit. Setiap output stasiun produksi ditampung dalam antrian untuk stasiun packing. Stasiun produksi tidak perlu menanti packing selesai untuk melanjutkan proses unit selanjutnya. Listing 103. Produksi dan Packing — job19f.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
Baris 74 sampai 87: stasiun packing secara berkala (300000 mikrodetik) memeriksa antrian untuk diproses. Baris 78: jika tidak ada antrian baru maka program menampilkan pesan packing... none. Baris 80 sampai 84: jika ada antrian baru maka stasiun packing memprosesnya.
Perhatikan lebih banyak baris packing... none dibandingkan packing.. done. Hal ini menunjukkan ketidakefisienan looping dalam subthread pack. Kesimpulan Dibutuhkan alternatif untuk singkronisasi antar thread yang lebih efisien.
Linux System Programming in C
142
Datatrans Informatika
40 Condition Variable
Tujuan Dapat membuat program singkronisasi multi thread yang lebih efisien menggunakan condition variable. Pada latihan sebelumnya kita telah membahas ketidakefisienan looping dalam singkronisasi antar thread. Kali ini kita menerapkan condition variable untuk menanggulanginya. Listing 104. Condition Variable — job19g.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
Baris 10: mencantumkan condition variable cond. Baris 21: deklarasi atribut condition variable cond_attr. Ini adalah atribut untuk menginisialisasi condition variable cond. Baris 36: menginisialisasi cond_attr. Di akhir program, atribut ini harus didestroy (baris 54). Baris 37: mengatur ruang ingkup cond_attr agar hanya dapat diakes di dalam proses yang tengah berlangsung (tidak dishared dengan prosesproses lain). Baris 38: menginisialisasi cond sesuai atribut cond_attr. Di akhir program, cond ini harus di destroy (baris 56). Baris 54: mendestroy atribut condition variable. Baris 56: mendestroy condition variable. Baris 72: subthread prod membangkitkan signal bagi condition variable. Subthread pack yang tengah diblock karena menanti signal tersebut dapat melanjutkan operasinya. Baris 85: subthread pack diblock menanti condition variable diberi signal oleh subthread prod. Mengenerate executable file: %
Perhatikan, subthread pack kali ini lebih efisien, tidak ada lagi packing... none. Kesimpulan Penggunaan condition variable dapat mengefisienkan singkronisasi antar thread. Tugas Eksplorasi 1. Pada latihan sebelumnya kita sudah membuat program multi thread untuk chat melalui serial port. Subthread recv memiliki loop yang belum efisien untuk membaca pesan yang diterima via serial port. Buatlah menjadi lebih efisien menggunakan condition variable. 2. Fungsi pthread_cond_signal memberi signal suatu condition variable dan mengunblock sebuah thread lain yang menantinya. Untuk mengunblock lebih dari satu thread, anda dapat menggunakan fungsi pthread_cond_broadcast. Buatlah program multi thread untuk simulasi berikut ini. Sebuah pabrik harus membuat N unit produk. Pabrik tersebut memiliki 1 unit shipping bertugas mengangkut bahan baku produksi dari supplier ke fasilitas produksi selama 10 detik. Pabrik tersebut memiliki 2 unit produksi. Sambil menanti bahan baku tiba, kedua unit produksi disetup selama masingmasing 5 detik dan 6 detik. Ketika bahan baku tiba, kedua unit produksi memprosesnya serentak dengan cycle time masingmasing 3 detik dan 2 detik.
Linux System Programming in C
145
Datatrans Informatika
41 Semaphore
Tujuan Dapat menggunakan metode semaphore untuk singkronisasi antar thread dalam program multi thread. Sebuah pabrik memiliki 3 station produksi dengan cycle time masingmasing 3 detik, 2 detik dan 4 detik. Setiap 1 unit yang selesai diproduksi harus diperiksa oleh auditor selama 3 detik. Karena hanya ada 2 auditor di pabrik tersebut maka harus ada singkronisasi antar station produksi. Pada latihan kali ini kita akan memanfaatkan metode semaphore. Listing 105. Semaphore — job19h.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
#include #include #include #include #include
<stdio.h> <semaphore.h> <stdlib.h>
typedef struct { int qty; pthread_mutex_t mtx; sem_t smp; } thdarg; typedef struct { thdarg* common; int statnum; int cycletime; } station; void* prod(void*); int main(int argc, char* argv[]) { pthread_t thd[3]; pthread_attr_t attr; struct sched_param param; pthread_mutexattr_t mtx_attr; thdarg arg; station stat[3]; int i; int* count; if(argc<2){ printf("please specify production qty\n"); return 1; }
printf("station %d, wait auditor\n", s->statnum); sem_wait(&p->smp); printf("...auditor starts on station %d\n", s->statnum); usleep(3000000); printf("...auditor done on station %d\n", s->statnum); sem_post(&p->smp); } pthread_exit((void*)count);
Baris 10: mencantumkan variabel semaphore smp ke dalam struktur thdarg. Baris 48: menginisialisasi semaphore dengan nilai 2 (banyaknya auditor). Di akhir program, semaphore harus didestroy. Baris 71: mendestroy semaphore. Baris 98: subthread menanti semaphore. Jika nilai semaphore lebih dari 0 maka subthread mendecrement semaphore dan melanjutkan kode berikutnya. Jika nilai semaphore kurang dari 1, subthread akan diblock. Baris 102: subthread mempost semaphore. Nilai semaphore diincrement sehingga dapat mengunblock thread lain yang menantinya. Mengenerate executable file: %
gcc -o job19h -Wall job19h.c -lpthread
Mengeksekusinya:
% ./job19h 5 1 station 1, prod. start 2 station 3, prod. start 3 station 2, prod. start 4 ...station 2, prod. done 5 station 2, wait auditor 6 ...auditor starts on station 2 7 ...station 1, prod. done 8 station 1, wait auditor 9 ...auditor starts on station 1 10 ...station 3, prod. done 11 station 3, wait auditor 12 ...auditor done on station 2 13 station 2, prod. start 14 ...auditor starts on station 3 15 ...auditor done on station 1 16 station 1, prod. start 17 ...station 2, prod. done 18 station 2, wait auditor 19 ...auditor starts on station 2 20 ...auditor done on station 3 21 ...station 1, prod. done 22 station 1, wait auditor 23 ...auditor starts on station 1 24 ...auditor done on station 2 25 ...auditor done on station 1 26 station 1 has produced 2 units 27 station 2 has produced 2 units 28 station 3 has produced 1 units
Perhatikan 2 auditor bekerja di 3 station secara bergantian. Kesimpulan
Linux System Programming in C
148
Datatrans Informatika
Semaphore digunakan sebagai metode singkronisasi antar thread. Tugas Eksplorasi Buatlah program berisi 1 main thread dan 10 subthread untuk mensimulasikan 10 orang mengantri di depan 2 mesin ATM. Lama tiap orang menggunakan mesin ATM tergantung banyaknya uang yang diambil tiap nasabah. Kedua ATM membutuhkan waktu 1 mikrodetik untuk memproses tiap rupiah. Gunakan metode singkronisasi semaphore untuk berbagi pakai mesin ATM.
Linux System Programming in C
149
Datatrans Informatika
42 Thread Pool
Tujuan Dapat membatasi banyaknya thread dalam suatu program menggunajan thread pool. Data dalam sebuah file berisi 1000 record akan diupload ke server database PostgreSQL. Tentu saja, lebih cepat jika tugas tersebut diselesaikan secara paralel dalam program multi thread. Makin banyak thread, makin cepat. Namun lebih banyak membutuhkan memori (secara default, stack memory 2 MB dialokasikan bagi tiap thread). Bagaimana cara membatasi jumlah maksimum thread dalam suatu program? Kita akan membahasnya dalam tema thread pool. Yang dimaksud dengan thread pool adalah sekelompok subthread dicreate dan running, menanti signal condition variable untuk memproses tugas. Tugastugas yang dikirim oleh main thread ditampung ke dalam queue. Setiap kali tugas disimpan ke dalam queue, main thread membangkitkan signal bagi condition variable. Listing 106. Thread Pool — pool.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
Baris 9: nama file berisi data terdiri atas 3 kolom. Pertama, nomor work order. Kedua, hasil pengukuran minimum hydro pressure. Ketiga, hasil pengukuran maximum hydro pressure. Tiap record diakhiri newline. Fieldfield dalam sebuah record dibatasi ; (semicolon). Baris 22: variabel antrian payload dicantumkan dalam argumen untuk subthread. Baris 70: baris pertama file berisi header sehingga diabaikan. Baris 77 sampai 81. Data dialokasikan di heap dan diberi nilai dari baris yang dibaca dari file. Baris 82: Data disimpan ke dalam queue. Jika queue penuh, tunda selama 0.1 detik dan kembali mencoba menyimpan data ke dalam queue. Baris 122: setiap kali sebuah data berhasil disimpan ke dalam queue, condition variable diberi signal. Baris 134 dan 135: subthread worker menanti signal condition variable. Jika signal bangkit dan ada antrian yang belum diproses maka subthread worker mengirim data ke server database PostgreSQL (baris 177). Tabel hydrotest dicreate di server database:
.PHONY: all clean all: pool pool: pool.o gcc -o pool -Wall pool.o -L/opt/pgsql/training/lib -lpq -lpthread pool.o: pool.c gcc -o pool.o -Wall -c pool.c -I/opt/pgsql/training/include/ clean: rm pool.o
Mengenerate executable file: %
make
Mengeksekusinya: % ./pool ... 2 seconds
Di komputer penulis (dual processor 1.2 GHz, RAM 4 GB), 1000 record dibaca dari file dan diupload ke server database dalam 2 detik. Jauh lebih cepat jika dikerjakan dalam single thread (20 detik). Kesimpulan Thread pool menghindari eksploitasi sumber daya komputer dengan membatasi jumlah maksimum subthread dalam suatu proses.
Linux System Programming in C
154
Datatrans Informatika
XII Multi Process
43 Fork 44 Duplikat Memori 45 Sub Program 46 Zombie Process 47 Pipe 48 Menghentikan Proses Background
Linux System Programming in C
155
Datatrans Informatika
43 Fork
Tujuan Dapat mengcreate sub process menggunakan fungsi fork. Sebelumnya kita telah mempelajari multithread. Yaitu, cara mengcreate subthread dari dalam main thread. Kali ini kita akan mempelajari multi process, cara mengcreate child process dari dalam main process. Linux menyediakan fungsi fork agar kita dapat menduplikasi proses yang tengah berlangsung dan menjadikannya proses baru. Listing 108. Fork — job20a.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
% ./job20a before fork: main parent pid 2635 main pid 4042 after fork, parent: main parent pid 2635 main pid 4042 after fork, child: child process parent pid 4042 child process pid 4043 hit any key
Perhatikan child process hasil fork (baris 4) memperoleh process id (PID) 4043 dan parent process id (PPID) 4042. Nomor tersebut menunjukkan parent process baris 3. Kesimpulan Main process dapat mengcreate sub process menggunakan fungsi fork.
Linux System Programming in C
157
Datatrans Informatika
44 Duplikat Memori
Tujuan Dapat memeriksa duplikat memori dari main process ke sub process. Jika main process memiliki variabelvariabel, bagaimanakah variabelvariabel tersebut diduplikasi ke dalam sub process. Listing 109. Duplikat Memori — job20b.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
printf("\tmain pid %u\n", main_after_fork_pid); usleep(10000); printf("\tmain value %p: %d\n", &value, value); printf("hit any key"); getchar(); } return 0; }
Mengenerate executable file: %
gcc -o job20b -Wall job20b.c
Mengeksekusinya:
% ./job20b 1 before fork: 2 main parent pid 2635 3 main pid 4312 4 main value 0x7fff9171b7b0: 10 5 after fork, parent: 6 main parent pid 2635 7 main pid 4312 8 after fork, child: 9 child process parent pid 4312 10 child process pid 4313 11 child value 0x7fff9171b7b0: 11 12 main value 0x7fff9171b7b0: 10 13 hit any key
Perhatikan variabel value. Baris 4: alamat dan nilai value dalam main process sebelum fork. Baris 11: di dalam child process, alamat value (0x7fff9171b7b0) sama seperti di dalam parent process. Namun, ini adalah virtual address space, bukan physical address space. Setelah diincrement, nilai value menjadi 11. Baris 12, kembali ke main process, nilai value tetap 10. Kesimpulan 1. Variabelvariabel di dalam main process diduplikat ke dalam child process. 2. Variabelvariabel tersebut berada di physical memory berbeda. Meskipun nilai variabel variabel tersebut sama ketika duplikasi, namun jika selanjutnya anda mengupdate nilai variabel di main process, tidak mengubah nilai di child process. Demikian pula sebaliknya.
Linux System Programming in C
159
Datatrans Informatika
45 Sub Program
Tujuan Dapat melaunch sub program melalui sub process.
45.1
Melaunch Sub Program
Kita dapat memanfaatkan fork untuk melaunch sub program menggunakan execvp. Listing 110. Execvp — job20c.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
Baris 7 sampai 10: inisialisasi argumen sub process. Elemen pertama adalah nama command yang akan dilaunch (mkdir). Elemen kedua dan ketiga adalah argumen tmp dan p. Jadi, command line mkdir akan menjadi sebagai berikut: %
mkdir tmp -p
Elemen keempat adalah NULL penanda akhir argumen sub process. Baris 12: fork untuk mengcreate sub process. Baris 19: di dalam sub process, melaunch mkdir menggunakan execvp.
Linux System Programming in C
160
Datatrans Informatika
Baris 20: menampilkan pesan gagal. Jika execvp berhasil melaunch sub program maka sequence kode tidak pernah singgah di baris ini. Baris 20: jika execvp gagal, fungsi abort mengclose semua stream yang masih terbuka. Mengenerate executable file: %
gcc -o job20c -Wall job20c.c
Mengeksekusinya: %
./job20c
Periksalah, kita telah mempunyai sub directory tmp.
45.2
Menanti Sub Program
Bagaimana jika main process ingin menanti sub program sebelum melanjutkan kode berikutnya? Misalnya, jika sub directory tmp berhasil dicreate maka main process melanjutkan tugas membuat file tmp/test. Listing 111. Menanti Sub Program dengan Wait — job20d.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
#include #include #include #include #include
<stdio.h> <stdlib.h> <sys/types.h> <sys/wait.h>
int main(int argc, char* argv[]) { char* args1[]={"mkdir", "tmp", NULL}; char* args2[]={"touch", "tmp/test", NULL}; int status; if (fork()==0) { execvp("mkdir", args1); printf("mkdir failed"); abort(); } wait(&status); if( !WIFEXITED(status) ) { printf("mkdir exit tidak normal\n"); return 1; } status=WEXITSTATUS(status); printf("mkdir exit dengan status %d\n", status); if(status==0){ if (fork()==0) { execvp("touch", args2); printf("touch failed"); abort(); } wait(&status); if( !WIFEXITED(status) ) { printf("touch exit tidak normal\n"); return 1; } status=WEXITSTATUS(status); printf("touch exit dengan status %d\n", status); } return 0; }
Linux System Programming in C
161
Datatrans Informatika
Baris 8: argumen untuk command line mkdir. Baris 9: argumen untuk command line touch. Baris 13: melaunch mkdir. Baris 17: menanti mkdir selesai. Baris 18: memastikan mkdir selesai secara normal. Baris 22: memeriksa return value dari mkdir, 0 berarti sukses. Baris 27: melaunch touch. Mengenerate executable file: %
gcc -o job20d -Wall job20d.c
Mengeksekusinya: terlebih dahulu hapus sub directory tmp. % rm -rf tmp % ./job20d mkdir exit dengan status 0 touch exit dengan status 0
Periksalah, kita telah mempunyai sub directory tmp dan file tmp/test. Jika dieksekusi sekali lagi: % ./job20d mkdir: cannot create directory ‘tmp’: File exists mkdir exit dengan status 1
Kesimpulan 1. Fork dan execvp bersamasama digunakan untuk melaunch sub program. 2. Main process dapat secara singkron menanti sub program selesai menggunakan fungsi wait.
Linux System Programming in C
162
Datatrans Informatika
46 Zombie Process
Tujuan 1. Memahami terjadinya zombie process. 2. Dapat mencegah zombie process. Untuk setiap sub process yang dicreate, Linux mendaftarkannya ke dalam process table. Guna menghemat daftar dalam process table maka entry sub process harus segera diclear jika selesai bertugas.
46.1
Zombie
Jika sub process berakhir lebih awal dari pada main process maka sub process tersebut menjadi zombie: masih memiliki entry dalam process table meskipun telah berakhir. Listing 112. Zombie Process — job20e.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
Baris 30: setelah satu detik, sub process berakhir. Baris 39: main process diblock, menanti ketukan tombol keyboard. Sebelum mengakhiri main process, kita berkesempatan memeriksa status sub process di dalam process table. Mengenerate executable file: %
gcc -o job20e -Wall job20e.c
Mengeksekusinya:
% ./job20e before fork: main parent pid 2632 main pid 2662 after fork, parent: main parent pid 2632 main pid 2662 after fork, child: child process parent pid 2662 child process pid 2663 hit any key
Sebelum mengetuk sembarang kunci untuk mengakhiri main process, mari memeriksa process table. Buka terminal baru, ketik command line: % 1 2 3 4
Perhatikan baris 4: sub process berstatus zombie (Z+ dalam kolom STAT). Sub process tersebut otomatik diclean dari process table jika main process berakhir.
46.2
Menanggulangi Zombie Process
Main process dapat mengclean up sub process yang telah berakhir dari process table menggunakan fungsi wait. Berikut ini adalah revisi kode untuk menanggulangi zombie process. Listing 113. Menghandle Signal SIGCHLD — job20f.c 1 2 3 4 5 6 7 8
Baris 7: variabel global child_terminated diinisialisasi dengan nilai 0 (ekuivalen dengan boolean FALSE). Baris 8: deklarasi fungsi child_handler untuk merespon signal SIGCHLD yang diterima oleh main process saat suatu sub process berakhir. Baris 26 sampai 30: mengassign fungsi child_handler untuk menghandle signal SIGCHLD. Linux System Programming in C
165
Datatrans Informatika
Baris 43: sub process sleep selama 1 detik sebelum berakhir. Ketika berakhir, main process menerima signal SIGCHLD. Baris 50 dan 51: main process berada dalam loop selama variabel child_terminated FALSE. Jika tengah berada dalam usleep maka main process akan diinterupsi oleh signal SIGCHLD. Baris 53: main process menanti ketukan sembarang tombol keyboard untuk mengakhiri proses. Baris ini memberi kita kesempatan untuk memeriksa process table. Jika selesai, ketik sembarang tombol. Baris 59 sampai 62: definisi child_handler. Fungsi wait memblock main process sampai sub process berakhir. Mengenerate executable file: %
gcc -o job20f -Wall job20f.c
Mengeksekusinya:
% ./job20f before fork: main parent pid 2632 main pid 5138 after fork, parent: main parent pid 2632 main pid 5138 after fork, child: child process parent pid 5138 child process pid 5139 hit any key
Jangan dulu mengetik sembarang kunci. Mari memeriksa process table: % ps ajxf PPID PID 2626 5257 5257 5288
PGID 5257 5288
SID TTY 5257 pts/0 5257 pts/0
TPGID STAT 5288 Ss 5288 S+
UID 1000 1000
TIME COMMAND 0:00 \_ bash 0:00 | \_ ./job20f
Perhatikan, tidak ada lagi zombie process. Kesimpulan 1. Sub process yang berakhir lebih awal dibandingkan main process akan menjadi zombie process. 2. Main process dapat mengclean up zombie process menggunakan signal SIGCHLD handler dan fungsi wait.
Linux System Programming in C
166
Datatrans Informatika
47 Pipe
Tujuan Dapat berkirim data antara main process dan sub process menggunakan pipe. Setelah sub process berhasil difork, main process dapat mengirim data ke sub process menggunakan pipe. Pipe adalah saluran data satu arah yang dapat diguakan untuk komunikasi antar proses. Fungsi pipe mengcreate saluran tersebut dengan mencantumkan 2 file descriptor ke dalam array berisi 2 elemen yang menjadi argumennya. Write end disimpan di index 1. Read end di index 0.
Baris 11: deklarasi array pipefd untuk menyimpan write end dan read end. Baris 17: mengcreate pipe. Baris 30: sub precess menanti data melalui read end. Baris 42: main process mengirim data melalui write end. Mengenerate executable file: %
gcc -o job20g -Wall job20g.c
Mengeksekusinya: % 1 2
./job20g main process:test message sub process:test message
Baris 1: di dalam main process, anda mengetik pesan diakhiri ENTER. Baris 2: sub process menerima pesan tersebut dan menampilkannya ke layar. Kesimpulan 1. Pipe adalah saluran data satu arah digunakan untuk komunikasi antar proses. 2. Pipe memiliki 2 ujung: write dan read end. 3. Proses mengirim pesan melalui write end. Proses lain menerima pesan melalui read end. Tugas Explorasi Buatlah program multi process yang berkomunikasi melalui pipe. Pengguna mengetik nama kota diakhiri ENTER dalam main process. Selanjutnya, main process mengirimkan nama kota tersebut ke sub process. Sub process menerima nama tersebut dan mencocokkan dalam daftar nama kota dan negara. Jika nama kota terdaftar maka sub process mengirimkan nama negara ke main process. Jika tidak, sub process mengirimkan “unknown” ke main process. Main process menampilkan nama negara.
Linux System Programming in C
168
Datatrans Informatika
48 Menghentikan Proses Background
Tujuan 1. Memahami signal untuk menghentikan proses background. 2. Dapat menghandle signal untuk menghentikan proses background. Kita dapat menghentikan suatu proses background dengan mengirimkan signal SIGTERM, atau SIGKILL ke proses tersebut. Signal SIGTERM mengizinkan kita menghandlenya menggunakan signal handler. Sedangkan, SIGKILL menghentikan proses seketika tanpa dapat dihandle. Listing 115. SIGTERM dan SIGKILL — job20h.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
Baris 18 dan 19: signal SIGTERM dan SIGKILL dihandle oleh fungsi term_handler. Baris 38 dan 29: jika signal yang dihandle adalah SIGTERM maka proses menampilkan pesan ke layar. Baris 39 dan 40: jika signal yang dihandle adalah SIGKILL maka proses menampilkan pesan ke layar. Mengenerate executable file: %
gcc -o job20h -Wall job20h.c
48.1
Mengirim Signal SIGTERM
Melaunching sub process: % ./job20h sub process 17901
Memeriksa process table:
% ps -e |grep job20h 17901 pts/1 00:00:00 job20h
Menghentikannya dengan signal SIGTERM: % kill -s TERM 17901 SIGTERM received sub process terminated properly
Memeriksa process table:
% ps -e |grep job20h 17901 pts/1 00:00:00 job20h
Menghentikannya dengan signal SIGTERM: % kill -s TERM 17901 SIGTERM received sub process terminated properly
Memeriksa process table sekali lagi untuk memastikan sub process telah berakhir: %
ps -e |grep job20h
Perhatikan, job20h tidak terdaftar lagi di dalam process table. Berikut ini alternatif untuk menghentikan proses dengan signal SIGTERM (process id 17901 hanya untuk contoh): % % %
kill -s 15 17901 kill 17901 killall job20h
48.2
Mengirim Signal SIGKILL
Melaunching sub process: % ./job20h sub process 18474
Menghentikannya dengan signal SIGKILL: %
kill -s KILL 18474
Signal SIGKILL tidak dapat dihandle oleh signal handler. Linux System Programming in C
170
Datatrans Informatika
Memeriksa process table: %
ps -e |grep job20h
Perhatikan, job20h tidak terdaftar lagi di dalam process table. Berikut ini alternatif untuk menghentikan proses dengan signal SIGKILL (process id 18474 hanya untuk contoh): % %
kill -s 9 18474 kill -9 18474
Kesimpulan 1. Jika dihentikan menggunakan signal SIGTERM, kita dapat menghandlenya menggunakan signal handler. 2. Jika dihentikan menggunakan signal SIGKILL, kita tidak dapat menghandlenya. Tugas Eksplorasi Diskusikan potensi masalah jika menghentikan proses menggunakan signal SIGKILL.
Linux System Programming in C
171
Datatrans Informatika
XIII Linux Daemon
49 Memprogram Daemon 50 Merekam Aktivitas ke System Log 51 Library untuk Launch Daemon dan Logging 52 Library untuk Memparse File Konfigurasi 53 Contoh Daemon
Linux System Programming in C
172
Datatrans Informatika
49 Memprogram Daemon
Tujuan Dapat membuat program daemon melalui multi process. Pada latihan sebelumnya kita telah mempelajari cara membuat sub process menggunakan fork. Kali ini kita akan memprogram daemon. Yaitu, suatu background process yang tidak berinteraksi dengan pengguna. Ada 3 langkah untuk membuat daemon: • Memfork parent process untuk menciptakan daemon. • Daemon melepaskan diri dari current session dan membuat session sendiri. • Daemon mengclose file descriptor standar karena tidak berinteraksi dengan pengguna. Listing 116. Daemon — job21a.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
pid_t fork_id; //1. fork parent process fork_id = fork(); if(fork_id==-1) { perror("fork failed"); exit(FAILED); } if(fork_id!=0)//main process exits immediately exit(SUCCESS); //2. detach from current session, create new session if(setsid()==-1) { perror("setsid failed"); exit(FAILED); } //3. close standard file descriptors close(STDIN_FILENO); close(STDOUT_FILENO); close(STDERR_FILENO); return; } void term_handler(int status) { if(status==SIGTERM) should_exit=TRUE; }
Baris 16: fungsi createdaemon bertugas memfork parent process untuk membuat sub process. Fungsi tersebut didefinisikan pada baris 33 sampai 58. Baris 18 sampai 22: jika createdaemon berhasil, sub process menghandle signal SIGTERM untuk menghentikan proses. Baris 24 dan 25: loop untuk simulasi proses di dalam daemon. Loop akan berakhir jika variabel should_exit diset TRUE ketika menghandle signal SIGTERM (baris 62). Baris 37: memfork parent process, menciptakan sub process yang akan menjadi daemon. Baris 43 dan 44: parent process langsung berakhir. Kode pada baris selanjutnya berlangsung di dalam daemon. Baris 47: daemon harus melepaskan diri dari current session dan menciptakan session sendiri. Baris 53 sampai 55: karena daemon tidak berinteraksi dengan pengguna maka file descriptor standar (stdin, stdout dan stderr) harus diclose. Mengenerate executable file: %
gcc -o job21a -Wall job21a.c
Melaunching daemon: %
./job21a
Memeriksa process table: % ps ajxf PPID PID 1 3920
PGID 3920
SID TTY 3920 ?
Linux System Programming in C
TPGID STAT -1 Ss
174
UID 1000
TIME COMMAND 0:00 ./job21a
Datatrans Informatika
Perhatikan, daemon (PID 3920) menjadi leader dalam group dan session baru (PGID dan SID 3920). Menghentikan daemon: %
kill -s TERM 3920
Kesimpulan 1. Program multi process dapat digunakan untuk melaunch daemon menggunakan fungsi fork. 2. Daemon harus didetach dari current session dan menciptakan session baru. 3. Daemon tidak berinteraksi dengan pengguna sehingga semua file descriptor standar harus diclose.
Linux System Programming in C
175
Datatrans Informatika
50 Merekam Aktivitas ke System Log
Tujuan Dapat merekam aktifitas daemon ke dalam system log. Daemon tidak berinteraksi dengan pengguna. Status aktivitas daemon tidak ditampilkan ke terminal. Kita dapat menampilkannya ke system log. Listing 117. System Log — job21b.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
//1. fork parent process fork_id = fork(); if(fork_id==-1) { perror("fork failed"); exit(FAILED); } if(fork_id!=0)//main process exits immediately exit(SUCCESS); //2. detach from current session, create new session if(setsid()==-1) { perror("setsid failed"); exit(FAILED); } //3. close standard file descriptors close(STDIN_FILENO); close(STDOUT_FILENO); close(STDERR_FILENO); return; } void term_handler(int status) { if(status==SIGTERM) should_exit=TRUE; }
Baris 5: syslog.h adalah header berisi deklarasi fungsifungsi untuk merekam aktivitas ke dalam system log. Baris 28: menginisialisasi koneksi dengan system logger. Baris 30: merekam aktivitas ke dalam system log. Baris 33: menutup koneksi dengan system logger. Mengenerate executable file: %
gcc -o job21b -Wall job21b.c
Melaunching daemon: %
./job21b
Menggunakan privilege root, periksalah system log: % tail -f /var/log/messages Nov 5 13:26:22 localhost journal: Nov 5 13:26:23 localhost journal: Nov 5 13:26:24 localhost journal: Nov 5 13:26:25 localhost journal: Nov 5 13:26:26 localhost journal:
Kesimpulan Karena tidak berinterkasi dengan user, daemon dapat merekam aktivitas ke dalam system log. Tugas Eksplorasi
Linux System Programming in C
177
Datatrans Informatika
Ubahlah target log dari system log ke file yang berotasi sesuai hari. Aktivitas hari Senin, sampai Minggu masingmasing direkam ke dalam job21bmon.log sampai job21bsun.log. Aktivitas Senin minggu berikutnya kembali direkam ke job21bmon.log setelah terlebih dahulu dihapus.
Linux System Programming in C
178
Datatrans Informatika
51 Library untuk Launch Daemon dan Logging
Tujuan Dapat membuat library untuk melaunch daemon dan merekam aktivitas ke dalam file log. Agar memudahkan menyelesaikan projek pembuatan daemon, mari membuat reusable library. Pada latihan ini kita akan membuat library statik. Anda dapat mengubahnya menjadi library dinamik17. Listing 118. Header — daemon.h 1 2 3 4 5 6 7
Baris 16 sampai 19: parent process difork untuk memulai daemon. Baris 22 dan 23: parent process berakhir. Barisbaris kode selanjutnya berlangsung dalam daemon. Baris 25 sampai 28: daemon didetach dari session parent process dan mengcreate session nya sendiri. Baris 30: mengatur file creation mode agar dimask dengan bilangan oktal 027. Artinya, mode file yang dicreate akan dimask: mode & ~027. Jika creation mode adalah 777 (read, write, execute untuk owner, group dan other) maka setelah di mask menjadi 750: • Read, write, execute hanya untuk owner. • Read dan execute untuk group. • Tidak ada hak akses bagi other. Baris 32 sampai 36: mengopen pidile. File ini berisi process id daemon. Baris 37: melock pidfile agar memastikan hanya ada satu daemon yang running. Jika mencoba merun daemon secara berganda maka akan gagal ketika mengopen pidfile (baris 32 sampai 36). Baris 41 dan 42: merekam process id ke dalam pidfile. Baris 44 sampai 46: mengclose file descriptor standar karena daemon tidak berinteraksi dengan user. Baris 51 sampai 92: merekam aktivitas daemon ke dalam file log dengan format nama file: [path]/[daemon_name][day].log. Untuk hari yang sama pada minggu berikutnya maka file log terlebih dahulu ditruncate. Listing 120. Makefile 1 2 3 4 5 6 7 8
Jika berhasil, anda memperoleh libdaemon.a. Kesimpulan Library untuk melaunch daemon dan logging akan memudahkan pembuatan projekprojek background service.
Linux System Programming in C
181
Datatrans Informatika
52 Library untuk Memparse File Konfigurasi
Tujuan Dapat membuat library untuk memparse file konfigurasi. Agar beroperasi sebagai background service, variabel untuk daemon diatur dalam file konfigurasi. Untuk struktur file konfigurasi yang kompleks, kita dapat menggunakan libconfig. Mari membuat library sendiri untuk memparse struktur file yang sederhana, misalnya: 1 2 3 4
#test
logpath = log delay =5000000
Baris 1 diabaikan karena teks diawali #. Baris 2 diabaikan karena baris kosong Baris 3 diparse menjadi: kunci logpath, nilai log. Whitespace di awal dan akhir kata ditrim. Baris 4 diparse menjadi: kunci delay, nilai 5000000. Listing 121. Header — conf.h 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
Jika berhasil, anda memperoleh libconf.a. Kesimpulan Library untuk memparse file konfigurasi memudahkan pembuatan aplikasi yang membutuhkan nilai variabel dari file konfigurasi.
Linux System Programming in C
185
Datatrans Informatika
53 Contoh Daemon
Tujuan 1. Dapat membuat daemon menggunajan library libdaemon dan libconf. 2. Dapat membuat initscript.
53.1
Daemon
Kita akan memanfaatkan library statik libdaemon dan libconf untuk membuat daemon bernama mydaemon. Listing 124. Daemon — mydaemon.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
Baris 1 dan 2: direktori tempat libdaemon dan libconf. Sesuaikan dengan instalasi di komputer and. Membuild daemon: %
make
Jika berhasil, anda memperoleh mydaemon. Untuk mencobanya, terlebih dahulu mari membuat direktory run dan log, masingmasing untuk path pidfile dan log file. Lalu, membuat file konfigurasi bernama job.conf: 1 2
logpath = log delay = 5000000
Baris 1: logpath adalah direktori tempat log file. Baris 2: delay adalah nilai mikrodetik untuk usleep selama infinite loop di dalam mydaemon. Melaunch mydaemon: %
./mydaemon run/mydaemon.pid job.conf
Untuk menghentikannya: %
killall mydaemon
53.2
Initscript
Untuk mendaftarkan mydaemon sebagai background service, mari membuat initscript bernama mydaemond. Listing 126. Initscript — mydaemond
#!/bin/bash # # chkconfig: 235 10 20 # description: starts and stops mydaemon BUILDDIR=/opt/course/job21/daemon CONFFILE=$BUILDDIR/job.conf DAEMON=mydaemon DAEMONPATH=$BUILDDIR/$DAEMON PIDFILE=$BUILDDIR/run/$DAEMON.pid DAEMONSCRIPT=mydaemond function isrunning() { if [ -f $PIDFILE ]; then if [ -h /proc/$(cat $PIDFILE)/exe ]; then return 0; fi fi return 1; } start() { if isrunning; then echo "$DAEMON aleady run" exit 1 fi $DAEMONPATH $PIDFILE $CONFFILE usleep 500000 if isrunning; then echo "$DAEMON launched successfully" else echo "$DAEMON failed" fi } stop() { local counter=0 while [ $counter -lt 3 ]; do killall $DAEMON usleep 500000 if ! isrunning; then echo "$DAEMON stopped" if [ -f $PIDFILE ]; then rm $PIDFILE fi return fi let counter=$counter+1; done echo "$DAEMON stop failed" exit 1 }
status() { if isrunning; then echo "$DAEMON is on" else echo "$DAEMON is off" fi } case "$1" in start) start ;; stop) stop ;; restart) stop start ;; status) status ;; *) echo "Usage: $DAEMONSCRIPT {start|stop|restart|status}" esac
Mode file mydaemond harus diset executable: %
chmod u+x mydaemond
Baris 1: menetapkan bash sebagai interpreter. Baris 3: jika didaftarkan sebagai system service maka mydaemond hanya valid untuk runlevel 2, 3 dan 518, distart pada urutan 10 dan distop pada urutan 20. Kita dapat memberi nomor antara 0 sampai 99. Untuk mendaftarkan mydaemond sebagai system service, copy file tersebut ke direktori /etc/init.d. Lalu daftarkan: %
chkconfig –add mydaemond
Baris 6: sesuaikan BUILDDIR dengan instalasi di komputer anda. Kita dapat menggunakan perintah baris: • mydaemond start, untuk melaunch daemon. • mydaemond stop, untuk menghentikan daemon. • mydaemond restart, untuk menghentikan dan melaunch daemon. • mydaemond status, untuk menampilkan status daemon. Kesimpulan 1. Initscript memudahkan pengaturan daemon. 2. Kita dapat membuat demon dan didaftarkan sebagai system service.
18 http://www.tldp.org/LDP/sag/html/run-levels-intro.html, Linux memilki runlevel sebagai berikut: 0: halt the system 1: single user mode 2: local multiuser with networking but without network service 3: full multi user with networking 4: not used 5: full multiuser with networking anc X Windows (GUI) 6: reboot Linux System Programming in C
Tujuan 1. Dapat mengcreate FIFO menggunakan command line. 2. Dapat menggunakan FIFO untuk komunikasi antar proses. Pada latihan sebelumnya, kita telah mengeksplorasi pipe untuk komunikasi antar proses19. Pipe adalah saluran komunikasi satu arah dengan dua ujung: read end dan write end. Kedua ujung diakses melalui file descriptor yang hanya dapat diakses oleh prosesproses yang terjalin melalui fork. FIFO (First In First Out) adalan named pipe. Kedua ujung saluran komunikasi dapat diakses menggunakan identitas nama oleh prosesproses yang tidak terkait. Ada 2 skenario komunikasi menggunakan FIFO: 1) writer close lebih awal, atau 2) reader close lebih awal.
54.1
Writer Close Lebih Awal Open FIFO: Read End
Open FIFO: Write End
Blocking: menanti Rread End
l unb
ock
unb l
ock
Blocking: menanti entry keyboard write FIFO
Blocking: menanti Write End
read FIFO
unblock unblock
close FIFO
Blocking: menanti Write End
print message
EOF: End Of File close FIFO
Gambar 14: Writer Close Lebih Awal
19 Lihat halaman 167. Linux System Programming in C
191
Datatrans Informatika
Write end dan read end adalah dua proses yang tidak terkait. Write end (sebelah kiri) akan di block ketika mengopen FIFO. Menanti read end mengopen FIFO. Demikian pula sebaliknya, jika read end diopen terlebih dahulu maka proses diblock menanti write end diopen. Read end membaca FIFO, diblocking menanti pesan dari write end. Pada proses write end, pengguna mengetik pesan menggunakan keyboard hingga tombol ENTER. Pesan ditulis ke FIFO. Read end diunblock, membaca pesan dari FIFO dan menampilkannya ke layar komputer. Read end kembali diblock, menanti pesan dari write end. Write end mengclose FIFO. Read end diunblock dan mendeteksi status End Of File pada FIFO. Read end mengclose FIFO.
54.2
Reader Close Lebih Awal Open FIFO: Read End
Open FIFO: Write End
Blocking: menanti Rread End
unb l
k loc unb
ock
Blocking: menanti entry keyboard write FIFO
Blocking: menanti Write End
Blocking: menanti Write End SIGPIPE
Ctrl+C SIGINT
Terminated
EPIPE error: Broken Pipe close FIFO
Gambar 15: Reader Close Lebih Awal Seperti dijelaskan sebelumnya, write end dan read end mengopen FIFO dan saling meng unblock. Kali ini kita mensimulasikan read end close lebih awal dengan cara menekan kombinasi tombol keyboard Ctrl C. Read end diterminate oleh signal SIGINT. Ketika pengguna di proses write end mengetik pesan di keyboard hingga menekan ENTER, write FIFO akan gagal. Write end menerima signal SIGPIPE serta kode error EPIPE (broken pipe).
54.3
Mengcreate FIFO
FIFO dapat dicreate menggunakan command line. %
mkfifo -m 666 myfifo
Hasilnya adalah sebuah file bertipe pipe: % ls -l |grep myfifo prw-rw-rw- 1 abdul abdul 0 Nov
9 09:00 myfifo
Di komputer penulis, path lengkap file tersebut adalah: /opt/course/job21/fifo/myfifo.
Buka dua terminal. Posisikan bersebelahan. Sebelah kiri untuk writer dan kanan untuk reader. % ./fifosend sender FIFO will wait for receiver FIFO
% ./fiforecv receiver FIFO will wait for sender FIFO
your message (EXIT to terminate):exit sender FIFO closed exit EOF receiver FIFO closed
Teks exit yang diketik pada write end mengakhiri loop write end dan mengclose FIFO.
Linux System Programming in C
194
Datatrans Informatika
Read end menerima pesan exit. Menampilkannya di layar komputer. Pada loop selanjutnya, read end mendeteksi End Of File (EOF) pada FIFO, mengakhiri loop dan mengclose FIFO.
54.7
Skenario 2: Reader Close Lebih Awal
Buka dua terminal. Posisikan bersebelahan. Sebelah kiri untuk writer dan kanan untuk reader. % ./fifosend sender FIFO will wait for receiver FIFO
% ./fiforecv receiver FIFO will wait for sender FIFO ^C
your message (EXIT to terminate):test SIGPIPE detected flush failed: 32 Broken pipe sender FIFO close
Pada proses read end, ketik kombinasi tombol Ctrl C (ditampilkan ^C di layar komouter). Read end diterminate. Teks test yang diketik pada write end dikirimkan melalui FIFO ke read end. Tetapi, write end menerima signal SIGPIPE. Pengiriman pesan gagal dengan kode error EPIPE (id 32, deskripsi: Broken pipe). Kesimpulan FIFO adalah pipe yang dapat digunakan oleh prosesproses yang tidak berkaitan untuk mengirim dan menerima pesan. Tugas Eksplorasi 1. Cobalah buka 2 terminal untuk fifosend dan 2 terminal lain untuk fiforecv. Apakah sebuah FIFO dapat dishare oleh beberapa writer dan beberapa reader. 2. Buatlah sebuah program client dan sebuah daemon. Program client mengirim perintah SQL melalui FIFO ke daemon dan menanti data untuk ditampilkan di layar. Daemon menerima perintah SQL lewat FIFO. Perintah SQL dikirim ke server PostgreSQL. Baik perintah SQL maupun data yang diterima dari server PostgreSQL disimpan ke dalam memori sebagai cache. Data dikirim melalui FIFO ke program client. Jika perintah SQL yang sama diterima lagi dari client, daemon cukup menggalinya dari cache tanpa perlu mengquery ke server PostgreSQL.
Linux System Programming in C
195
Datatrans Informatika
55 File Locking
Tujuan Dapat menggunakan file locking untuk mengatur akses file oleh lebih dari satu proses. File locking mengatur akses file oleh lebih dari satu proses. Sebelum mengupdate atau membaca isi file, setiap proses harus memperoleh lock. File locking memungkinkan proses untuk melock area tertentu di dalam file.
55.1
Append
Beberapa proses dapat mengappend data ke dalam sebuah file. Contoh, kita mempunyai sebuah file berisi recordrecord WO (work order) yang fixed length. File tersebut akan di append oleh lebih dari satu proses. Listing 129. Struktur Work Order — wo.h 1 2 3 4 5 6 7 8 9 10 11
write(fd, &ctwo, sizeof(wo)); printf("hit any key to release lock:"); getchar(); fl.l_type = F_UNLCK; fcntl(fd, F_SETLK, &fl);//unlock close(fd); return 0; }
File locking diimplementasikan sebagai berikut: • Baris 11: deklarasi variabel fl dengan tipe data struktur flock. • Baris 21: elemen l_type diset F_WRLCK, artinya lock diperoleh untuk write. • Baris 22: elemen l_whence diset SEEK_END, artinya file dilock pada posisi end of file. • Baris 23: elemen l_start diset 0, artinya file dilock mulai offset 0 byte relatif terhadap l_whence. • Baris 24: elemen l_len diset 0, artinya file dilock sehingga mencapai end of file. • Baris 29: melock file untuk writing. Proses akan diblok jika ada proses lain yang masih memegang lock. • Baris 37 dan 38: merelease lock. Membuild program: %
gcc -o append -Wall append.c -I.
Untuk menguji program tersebut, bukalah dua terminal. Posisikan bersebelahan: % ./append nomor wo dan qty:WHT100 200 get lock lock acquired hit any key to release lock:
% ./append nomor wo dan qty:WHT150 300 get lock
Proses sebelah kanan diblock menanti proses sebelah kiri merelease lock. Memeriksa isi file wo.dat: % od -tx1c wo.dat 0000000 57 48 54 W H T 0000020 35 30 00 5 0 \0 0000030
31 1 00 \0
30 30 0 0 2c 01 , 001
00 \0 00 \0
00 c8 \0 310 00 \0
00 \0
00 \0
00 \0
57 W
48 H
54 T
31 1
File telah berisi 2 record dengan total ukuran 24 byte.
55.2
Write di Area File Tertentu
Linux System Programming in C
197
Datatrans Informatika
Karena file locking mengizinkan lock pada area tertentu maka dua proses dapat secara bebas melock area yang berbeda secara bersamaan. Contoh, proses pertama dan kedua masingmasing melock dan mengupdate record pertama dan kedua. Listing 131. Write di Area File — edit.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
Area locking ditentukan sebagai berikut: • Baris 26: l_whence diset SEEK_SET (beginning of file). • Baris 27: l_start diset ke awal area file yang akan dilock. • Baris 28: l_len diset sesuai ukuran struktur data wo (kita hanya akan membaca dan meng update satu record). Membuild program: %
gcc -o edit -Wall edit.c -I.
Untuk menguji program tersebut, bukalah dua terminal. Posisikan bersebelahan: % ./edit record number:1 get lock lock acquired wo number: WHT100, qty: 200 nomor wo dan qty:WHT101 201 hit any key to release lock:
% ./edit record number:2 get lock lock acquired wo number: WHT150, qty: 300 nomor wo dan qty:WHT151 301 hit any key to release lock:
Proses sebelah kiri dan kanan dapat secara serentak melock record di area yang berbeda. Jika kedua proses berusaha melock area file yang sama maka salah satu proses berhasil memperoleh lock lebih dahulu, proses lain diblock menanti lock direlease.
55.3
Read di Area File Tertentu
Selain lock untuk write, file locking juga menyediakan pilihan untuk read lock. Listing 132. Read di Area File — read.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
Read locking ditentukan pada baris 24: l_type diset F_RDLCK. Membuild program: %
gcc -o read -Wall read.c -I.
Untuk menguji program tersebut, bukalah dua terminal. Posisikan bersebelahan: % ./read record number:1 get lock lock acquired wo number: WHT101, qty: 201 hit any key to release lock:
% ./read record number:1 get lock lock acquired wo number: WHT101, qty: 201 hit any key to release lock:
Proses sebelah kiri dan kanan dapat secara serentak melock record yang sama. Kesimpulan File locking digunakan untuk mengatur akses file oleh lebih dari satu proses.
Linux System Programming in C
200
Datatrans Informatika
Tugas Eksplorasi 1. Apa yang terjadi jika satu proses melock area file yang sama dengan jenis lock berbeda. Proses pertama melock untuk read, proses kedua melock untuk write. Lakukan 2 percobaan. Pertama, read lock terlebih dahulu dan write lock kemudian. Kedua, write lock terlebih dahulu dan read lock kemudian. 2. Buatlah dua program. Pertama, merekam data ke dalam file. Kedua, secara berkala membaca file yang sama dan mengupload ke server database PostgreSQL.
Linux System Programming in C
201
Datatrans Informatika
56 Message Queue
Tujuan Dapat menggunakan message queue untuk komunikasi antar proses. Message queue adalah salah satu metode komunikasi antar proses. Untuk memulai komunikasi, queue terlebih dahulu harus dicreate dan diberi nomor identitas. Selanjutnya, proses dapat menyimpan berbagai struktur data ke dalam queue dengan memberi nomor unik untuk tiap struktur data. Kita akan membuat 3 program. Pertama, program untuk mengcreate dan mendestroy queue. Kedua, program untuk menyimpan data dengan tipe struktur data berbeda ke dalam queue. Ketiga, program untuk memungut data dari queue sesuai tipe struktur data yang dikehendaki.
56.1
Struktur untuk Queue Key
Queue diakses menggunakan bilangan key yang unik. Linux menyediakan library untuk memperoleh key berdasarkan filepath dan nomor projek. Mari mempersiapkan filepath que: %
touch que
Selanjutnya kita mempersiapkan simbol KEY_PATH (que) dan KEY_PROJ (1) yang akan digunakan dalam programprogram yang akan dibuat. Kita dapat memilih bilangan integer lain dengan syarat: nonzero 8 least significant bits. Listing 133. Filepath dan Project untuk Generate Key — key.h 1 2 3 4 5 6 7
int id; k=ftok(KEY_PATH, KEY_PROJ); if(k==-1){ perror("queue key"); return 1; } id=msgget(k, IPC_CREAT|IPC_EXCL|0666); if(id==-1) { perror("queue create"); return 1; } printf("queue id %d, hit any key to destroy queue", id); getchar(); if(msgctl(id, IPC_RMID, NULL)==-1) perror("queue destroy"); return 0; }
Baris 12: mengenerate key berdasarkan KEY_PATH dan KEY_PROJ yang didefinisikan dalam header key.h. Baris 18: mengcreate queue dengan permission 666 (owner, group dan other berhak untuk read dan write). Baris 24: menanti ketikan keyboard untuk menghentikan program, memberi kesempatan bagi program lain untuk menulis atau membaca data dari queue. Baris 26: mendestroy queue. Membuild program: %
gcc -o create -Wall create.c -I.
Untuk menguji program, persiapkan dua terminal bersebelahan. Sebelah kiri untuk melaunch create. Sebelah kanan untuk memeriksa fasilitas IPC (Inter Process Communication) yang terdaftar dalam sistem operasi: % ./create queue id 98304, hit any key to destroy % ipcs -q queue ------ Message Queues -------key msqid owner perms 0x0101447e 98304 abdul 666
Data yang akan disimpan ke dalam queue harus berupa struktur data dengan definisi sebagai berikut: struct msgbuf { long mtype; char mtext[1]; };
Linux System Programming in C
/* message type, must be > 0 */ /* message data */
203
Datatrans Informatika
Elemen mtype harus bilangan positif. Elemen mtext boleh diisi array atau strukur data. Contoh, kita akan mengirimkan 2 data ke dalam queue dengan struktur data berbeda, yaitu WO (Work Order) dan PO (Purchase Order). Terlebih dahulu mari membuat header: Listing 135. Struktur Data untuk Queue — data.h 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
#ifndef _DATA_H_ #define _DATA_H_ #define WO_NO_LEN 7 #define PO_NO_LEN 7 #define CUSTOMER_LEN 20 #define WO_DATA_TYPE 1 #define PO_DATA_TYPE 2 typedef struct { char no[WO_NO_LEN+1]; int qty; } wo; typedef struct { char po[PO_NO_LEN+1]; char customer[CUSTOMER_LEN+1]; int qty; } po; typedef struct { long mtype; wo data; } wo_que; typedef struct { long mtype; po data; } po_que; #endif
Selanjutnya, mari membuat program pengirim data Work Order dan Purchase Order ke queue. Listing 136. Mengirim Data Work Order ke Queue — sendwo.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
Baris 27: meraih queue dengan permission 444 (write untuk owner, group dan other). Baris 33: elemen mtype diset WO_DATA_TYPE yang didefinisikan dalam data.h. Baris 34 da 35: mengisi nomor dan quantity work order. Baris 37: mengirim data ke queue. Perhatikan, argumen ketiga berisi ukuran data struktur wo bukan wo_que. Membuild program: %
Baris 27: meraih queue dengan permission 444 (write untuk owner, group dan other). Baris 33: elemen mtype diset PO_DATA_TYPE yang didefinisikan dalam data.h. Baris 34 da 36: mengisi nomor, nama customer dan quantity purchase order. Baris 38: mengirim data ke queue. Perhatikan, argumen ketiga berisi ukuran data struktur po bukan po_que. Membuild program: %
gcc -o sendpo -Wall sendpo.c -I.
Untuk menguji program sendwo dan sendpo, persiapkan dua terminal bersebelahan. Sebelah kiri untuk melaunch create. Sebelah kanan untuk melaunch sendwo dan sendpo serta memeriksa fasilitas IPC (Inter Process Communication) yang terdaftar dalam sistem operasi: % ./create queue id 229376, hit any key to destroy queue
% ipcs -qu ------ Messages Status -------allocated queues = 1 used headers = 0 used space = 0 bytes % ./sendwo WHT100 100 % ipcs -qu ------ Messages Status -------allocated queues = 1 used headers = 1 used space = 12 bytes % ./sendpo PO100 VAL 200 % ipcs -qu allocated queues = 1 used headers = 2 used space = 48 bytes
tekan tombol ENTER untuk mendestroy queue.
Linux System Programming in C
% ipcs -qu ------ Messages Status -------allocated queues = 0 used headers = 0 used space = 0 bytes
206
Datatrans Informatika
Perhatikan terminal kanan, used space bertambah sesuai ukuran struktur data yang disimpan ke dalam queue. Setelah sendwo, used space menjadi 12 bytes (ukuran struktur wo). Setelah sendpo, used space menjadi 48 bytes (ukuran struktur wo plus po).
56.4
Memungut Data
Setelah berhasil mengirimkan data ke queue. Kini kita akan membuat 2 program untuk memungut data dari queue: sendwo dan sendpo. Listing 138. Memungut Data Work Order dari Queue — readwo.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
Baris 27: meraih queue dengan permission 222 (read untuk owner, group dan other). Baris 29: memungut data dengan tipe WO_DATA_TYPE (argumen ke4) dari queue. Argumen ke5 (IPC_NOWAIT) mengatur agar msgrcv bersifat nonblocking. Jika tidak maka program akan diblock sampai queue memiliki data dengan tipe yang diharapkan. Membuild program: %
gcc -o readwo -Wall readwo.c -I.
Listing 139. Memungut Data Purchase Order dari Queue — readpo.c 1
Baris 27: meraih queue dengan permission 222 (read untuk owner, group dan other). Baris 29: memungut data dengan tipe PO_DATA_TYPE (argumen ke4) dari queue. Argumen ke5 (IPC_NOWAIT) mengatur agar msgrcv bersifat nonblocking. Jika tidak maka program akan diblock sampai queue memiliki data dengan tipe yang diharapkan. Membuild program: %
gcc -o readpo -Wall readpo.c -I.
Untuk menguji program readwo dan readpo, persiapkan dua terminal bersebelahan. Sebelah kiri untuk melaunch create. Sebelah kanan untuk melaunch sendwo, sendpo, readwo dan readpo serta memeriksa fasilitas IPC (Inter Process Communication) yang terdaftar dalam sistem operasi: % ./create queue id 491520, hit any key to destroy queue
Linux System Programming in C
% ./sendwo WHT100 100 % ./sendpo PO200 VAL 200 % ipcs -qu ------ Messages Status -------allocated queues = 1 used headers = 2
208
Datatrans Informatika
used space = 48 bytes % ./readpo PO: PO200 Customer: VAL qty: 200 % ipcs -qu ------ Messages Status -------allocated queues = 1 used headers = 1 used space = 12 bytes % ./readpo read po: No message of desired type % ./readwo WO: WHT100 qty: 100 % ipcs -qu ------ Messages Status -------allocated queues = 1 used headers = 0 used space = 0 bytes % ./readwo read wo: No message of desired type
tekan tombol ENTER untuk mendestroy queue. Perhatikan terminal kanan, setiap data yang dipungut akan dihapus dari queue. Kesimpulan 1. Message queue dicreate dengan menetapkan indikator unik dan mode permission. 2. Message disimpan ke dalam dan dipungut dari queue berdasarkan bilangan yang mengindikasikan tipe struktur data. 3. Setiap data yang dipungut akan dihapus dari queue. Tugas Eksplorasi 1. Cobalah menyimpan 5 data ke dalam queue dengan tipe yang sama tetapi nilai yang berbeda . Periksalah, apakah data dipungut dari queue secara FIFO (First In First Out). 2. Pada bab ini kita telah membuat 3 jenis program: 1) create: untuk mengcreate dan mendestroy message queue, 2) sendpo dan sendwo: untuk mengirim data ke queue, 3) readwo dan readpo: untuk memungut data dari queue. Ubahlah program pertama (create) menjadi daemon.
Linux System Programming in C
209
Datatrans Informatika
57 Shared Memory Segment
Tujuan 1. Dapat mengcreate dan mendestroy shared memory segment. 2. Dapat mengakses data yang dialokasikan di shared memory segment. Shared memory segment adalah area memori yang dapat dishare antar proses. Jika suatu data dialokasikan dalam segmen tersebut maka beberapa proses dapat mensharenya.
57.1
Struktur untuk Key
Sebagaimana message queue, shared memory segment dicreate dan diakses menggunakan bilangan key yang unik. Kembali kita menggunakan filepath dan nomor projek untuk mengenerate key20. Mari mempersiapkan filepath shm: %
touch shm
Selanjutnya kita mempersiapkan simbol KEY_PATH (shm) dan KEY_PROJ (1) yang akan digunakan dalam programprogram yang akan dibuat. Listing 140. Filepath dan Project untuk Generate Key — key.h 1 2 3 4 5 6 7
20 Lihat halaman 202. Linux System Programming in C
210
Datatrans Informatika
13 14 15 16 17
short count; wo data[MAX_WO_ENTRY]; } shm_wo; #endif
Baris 4: MAX_WO_ENTRY didefinisikan 100. Artinya, maksimum 100 work order yang akan dialokasikan dalam shared memory segment. Baris 5: WO_NO_LEN adalah panjang maksimum nomor work order. Baris 7 sampai 10: definisi struktur data wo (work order). Baris 12 sampai 15: definisi struktur data yang akan dialokasikan dalam shared memory segment. Struktur berisi 2 elemen: count dan array data. Elemen count adalah variabel yang menunjukkan banyaknya work order yang ada dalam array data. Saat inisialisasi, count bernilai 0. Variabel count diincrement setiap kali suatu proses menabung work order baru ke dalam array data (tidak boleh melebihi MAX_WO_ENTRY).
int main(int argc, char* argv[]) { key_t k; int shmid; k=ftok(KEY_PATH, KEY_PROJ); if(k==-1) { perror("ftok"); return 1; } printf("shared memory segment request, size %lu\n", sizeof(shm_wo)); shmid = shmget(k, sizeof(shm_wo), IPC_CREAT|IPC_EXCL|0666); if(shmid==-1){ perror("shmget"); return 1; } printf("shared memory segment created with id %d\n", shmid); printf("hit ENTER to destroy shared memory segment:"); getchar(); shmctl(shmid, IPC_RMID, NULL); return 0; }
Baris 12: mengenerate key. Baris 20: mengcreate shared memory segment. Baris 28: menanti ketukan tombol ENTER. Linux System Programming in C
211
Datatrans Informatika
Baris 30: mendestroy shared memory segment. Membuild program: %
gcc -o create -Wall create.c -I.
Untuk menguji program, persiapkan dua terminal bersebelahan. Sebelah kiri untuk melaunch create. Sebelah kanan untuk memeriksa fasilitas IPC (Inter Process Communication) yang terdaftar dalam sistem operasi: % ./create shared memory segment request, size 1204 shared memory segment created with id 6357006 hit ENTER to destroy shared memory segment: % ipcs -m -i 6357006 Shared memory Segment shmid=6357006 uid=1000 gid=1000 cuid=1000 cgid=1000 mode=0666 access_perms=0666 bytes=1204 lpid=0 cpid=15017 nattch=0 att_time=Not set det_time=Not set change_time=Sat Nov 15 12:31:08 2014
tekan tombol ENTER untuk mendestroy queue. Periksa sekali lagi:
Baris 22: mengenerate key. Baris 28: mengakses shared memory segment menggunakan key. Baris 34: mengattach shared memory segment. Yaitu, meraih alamat awal memory dan menyimpannya dalam pointer p. Baris 40: mengcasting tipe pointer dari void* menjadi shm_wo*. Baris 43: meraih pointer untuk data work order baru. Baris 44 dan 45: menggunakan pointer untuk mengupdate data work order di shared memory segment. Baris 50: menanti ketukan tombol ENTER. Baris 52: mendetach shared memory segment. Membuild program: %
Baris 22: mengenerate key. Baris 28: mengakses shared memory segment menggunakan key. Baris 34: mengattach shared memory segment. Yaitu, meraih alamat awal memory dan menyimpannya dalam pointer p. Baris 40: mengcasting tipe pointer dari void* menjadi shm_wo*. Baris 42: menyalin nomor record dari argumen command line. Baris 43 sampai 46: jika nomor record tidak melampaui banyaknya record yang telah ditabung ke dalam shared memory segment, maka tampilkan data work order sesuai nomor record. Baris 51: menanti ketukan tombol ENTER. Baris 53: mendetach shared memory segment.
Linux System Programming in C
214
Datatrans Informatika
Membuild program: %
gcc -o readwo -Wall readwo.c -I.
57.6
Mengujicoba Program
Untuk menguji program, persiapkan tiga terminal bersebelahan. Sebelah kiri untuk melaunch create. Tengah untuk memeriksa fasilitas IPC (Inter Process Communication) yang terdaftar dalam sistem operasi. Sebelah kanan untuk melaunch sendwo dan readwo. % ./create shared memory segment request, size 1204 shared memory segment created with id 9404435 hit ENTER to destroy shared memory segment: % ipcs -m -i 9404435 Shared memory Segment shmid=9404435 uid=1000 gid=1000 cuid=1000 cgid=1000 mode=0666 access_perms=0666 bytes=1204 lpid=0 cpid=9471 nattch=0 att_time=Not set det_time=Not set change_time=Sat Nov 15 16:10:21 2014 % ./sendwo WHT100 100 wo count 0 hit ENTER to detach from shared memory segment: % ipcs -m -i 9404435 Shared memory Segment shmid=9404435 uid=1000 gid=1000 cuid=1000 mode=0666 access_perms=0666 bytes=1204 lpid=15851 cpid=9471 att_time=Sat Nov 15 16:14:56 2014 det_time=Not set change_time=Sat Nov 15 16:10:21 2014
cgid=1000 nattch=1
tekan tombol ENTER untuk men detach shared memory segment. % ipcs -m -i 9404435 Shared memory Segment shmid=9404435 uid=1000 gid=1000 cuid=1000 mode=0666 access_perms=0666 bytes=1204 lpid=15851 cpid=9471 att_time=Sat Nov 15 16:14:56 2014 det_time=Sat Nov 15 16:20:42 2014 change_time=Sat Nov 15 16:10:21 2014
cgid=1000 nattch=0
% ./readwo 1 wo count 1 WO No. WHT100 WO Qty. 100 hit ENTER to detach from shared memory segment: % ipcs -m -i 9404435 Shared memory Segment shmid=9404435 uid=1000 gid=1000 cuid=1000 mode=0666 access_perms=0666 bytes=1204 lpid=27977 cpid=9471 att_time=Sat Nov 15 16:22:14 2014 det_time=Sat Nov 15 16:20:42 2014 change_time=Sat Nov 15 16:10:21 2014
Linux System Programming in C
215
cgid=1000 nattch=1
Datatrans Informatika
tekan tombol ENTER untuk men detach shared memory segment. % ipcs -m -i 9404435 Shared memory Segment shmid=9404435 uid=1000 gid=1000 cuid=1000 mode=0666 access_perms=0666 bytes=1204 lpid=27977 cpid=9471 att_time=Sat Nov 15 16:22:14 2014 det_time=Sat Nov 15 16:26:08 2014 change_time=Sat Nov 15 16:10:21 2014
cgid=1000 nattch=0
tekan tombol ENTER untuk mendestroy shared memory segment. % ipcs -m -i 9404435 ipcs: id 9404435 not found
Kesimpulan Shared memory segment adalah tempat alokasi data yang dapat dishare oleh beberapa proses.
Linux System Programming in C
216
Datatrans Informatika
58 Semaphore
Tujuan 1. Dapat mengcreate dan mendestroy semaphore. 2. Dapat menggunakan semaphore untuk mencegah konflik akses data antar proses. Pada latihan sebelumnya kita telah mempelajari shared memory segment sebagai tempat alokasi data yang dapat dishare oleh beberapa proses. Kali ini kita akan mempelajari semaphore untuk mengatur akses data agar tidak terjadi race condition seperti yang pernah dipelajari dalam materi multi thread21. Pada latihan sebelumnya kita telah membuat program untuk mengappend data work order. Salah satu variabel penting dalam struktur shm_wo adalah count22 yang selalu diincrement setiap kali sebuah data workorder diappend. Nilai count berpotensi tidak konsisten jika lebih dari satu proses mengupdatenya secara bersamaan (race condition23).
58.1
Mengcreate dan Mendestroy Semaphore
Kita menyisipkan kode untuk mengcreate dan mendestroy semaphore ke dalam create.c yang telah dibicarakan dalam bab Shared Memory Segment 24. Listing 145. Mengcreate dan Mendestroy Semaphore — create.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
union semun { int val; struct semid_ds *buf; unsigned short *array; struct seminfo *__buf; }; int main(int argc, char* argv[]) { key_t k; int shmid, semid; union semun semarg;
Kodekode baru yang ditambahkan untuk mengcreate, menginisialisasi dan mendestroy semaphore adalah sebagai berikut: Baris 5: menginclude sys/sem.h. Baris 9 sampai 14: mendefinisikan union semun untuk inisialisasi semaphore (baris 32 dan 33). Baris 18: menambahkan variabel semid untuk menyimpan id semaphore. Baris 19: mendeklarasikan variabel semarg dengan tipe union semun. Baris 27: mengcreate semaphore, memanfaatkan key yang sama seperti digunakan untuk mengenerate shared memory segment (baris 37). Baris 32 dan 33: menginisialisasi semaphore dengan nilai 1. Baris 40 dan 48: mendestroy semaphore. Membuild program: %
gcc -o create -Wall create.c -I.
58.2
Menyimpan Data dengan Proteksi Semaphore
Kita menyisipkan kode untuk memanfaatkan semaphore dalam sendwo.c yang telah dibicarakan dalam bab Shared Memory Segment25. 25 Lihat halaman 212. Linux System Programming in C
printf("hit ENTER to detach from shared memory segment:"); getchar(); shmdt(p); sb.sem_op=1; semop(semid, &sb, 1); printf("semaphore unlocked\n"); return 0; }
Kodekode baru yang ditambahkan untuk melock dan mengunlock semaphore adalah sebagai berikut: Baris 5: menginclude sys/sem.h. Baris 13: menambahkan variabel semid untuk menyimpan id semaphore. Baris 17: mendeklarasikan variabel sb dengan tipe struktur sembuf. Baris 30: mengakses semaphore dan menyimpan indikatornya ke dalam semid. Baris 35 sampai 37: mempersiapkan data dalam sb untuk melock semaphore. Baris 39: melock semaphore dengan cara mendecrement nilainya. Proses diblock jika ada proses lain yang terlebih dahulu berhasil melocknya, menanti sampai semaphore diunlock. Baris 68 dan 69: semaphore diunlock dengan cara mengincrement nilanya. Membuild program: %
gcc -o sendwo -Wall sendwo.c -I.
58.3
Mengujicoba Program
Untuk menguji program, persiapkan tiga terminal bersebelahan. Sebelah kiri untuk melaunch create. Tengah dan kanan untuk sendwo. % ./create shared memory segment request, size 1204 shared memory segment created with id 9633799 hit ENTER to destroy semaphore and shared memory segment: % ./sendwo WHT100 100 % ./sendwo WHT200 200 wait semaphore wait semaphore semaphore locked wo count 0 hit ENTER to detach from shared memory segment:
tekan tombol ENTER untuk mendetach shared memory segment. semaphore unlocked
semaphore locked wo count 1 hit ENTER to detach from shared memory segment:
tekan tombol ENTER untuk mendetach shared memory segment. semaphore unlocked
Linux System Programming in C
220
Datatrans Informatika
tekan tombol ENTER untuk mendestroy shared memory segment. Perhatikan, sendwo pada terminal kanan diblock sampai sendwo di terminal tengah meng unlock semaphore. Kesimpulan Semaphore dapat digunakan untuk singkronisasi antar proses. Tugas Eksplorasi Kita telah membuat 3 program: 1) create untuk mengcreate dan mendestroy shared memory segment, 2) sendwo untuk menyimpan data ke dalam shared memory segment, 3) readwo untuk menyimpan data ke dalam shared memory segment. Ubahlah create menjadi daemon.
Linux System Programming in C
221
Datatrans Informatika
59 Memory Mapped File
Tujuan Dapat menggunakan memory mapped file untuk komunikasi antar proses yang direkam ke dalam file. Pada latihan sebelumnya kita telah mengeksplorasi shared memory segment26 untuk komunikasi antar proses. Kali ini kita akan membahas memory mapped file. Metode ini tidak hanya mengizinkan beberapa proses menshare data. Tetapi juga merekam data tersebut ke dalam file.
59.1
Struktur Data
Kembali kita memilih tema work order. Sama seperti yang digunakan dalam shared memory segment27: Listing 147. Struktur Data Work Order — data.h 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
#ifndef _DATA_H_ #define _DATA_H_ #define MAX_WO_ENTRY 100 #define WO_NO_LEN 7 typedef struct { char no[WO_NO_LEN+1]; int qty; } wo; typedef struct { short count; wo data[MAX_WO_ENTRY]; } wo_arr; #endif
Baris 4: MAX_WO_ENTRY didefinisikan 100. Artinya, maksimum 100 work order yang akan disimpan ke dalam file. Baris 5: WO_NO_LEN adalah panjang maksimum nomor work order. Baris 7 sampai 10: definisi struktur data wo (work order). Baris 12 sampai 15: definisi struktur data yang akan disimpan ke dalam file. Struktur berisi 2 elemen: count dan array data. Elemen count adalah variabel yang menunjukkan banyaknya work order yang ada dalam array data. Saat inisialisasi, count bernilai 0. Variabel count di 26 Lihat halaman 210. 27 Lihat halaman 210. Linux System Programming in C
222
Datatrans Informatika
increment setiap kali suatu proses menabung work order baru ke dalam array data (tidak boleh melebihi MAX_WO_ENTRY).
59.2
Header untuk Operasi Data
Kita merencanakan 3 operasi untuk mengelola data work order, yaitu: read, append dan edit. Ketiga operasi tersebut dideklarasikan dalam file header: Listing 148. Header Operasi Data — opr.h 1 2 3 4 5 6 7 8
Berikut ini adalah kode untuk membaca work order pada index tertentu. Pengguna meng entry nomor index record (mulai dari 1), program menampilkan nomor dan quantity work order sesuai index tersebut. Listing 149. Read Work Order — read.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
#include #include <stdio.h> void woread(const wo_arr* parr) { int idx; const wo* pwo; if(parr->count < 1){ printf("no records available\n"); return; } printf("record number [1 to %d]: ", parr->count); scanf("%d", &idx); while ( getchar() != '\n' );//clear stdin if(idx<1 || idx > parr->count) { printf("invalid record number %d\n", idx); return; } pwo=parr->data+(idx-1); printf("WO Number: %s\n", pwo->no); printf("WO Qty: %d\n", pwo->qty); return; }
Baris 810: jika tidak ada data work order maka fungsi segera berakhir. Baris 13 sampai 15: menerima input dari pengguna untuk nomor index record yang akan ditampilkan. Baris 17 sampai 19: jika nomor index di luar jangkauan yang valid maka fungsi segera berakhir. Linux System Programming in C
223
Datatrans Informatika
Baris 22: memungut pointer data work order sesuai index. Baris 23 dan 24: menggunakan pointer, menampilkan nomor dan quantity work order.
59.4
Append
Pengguna mengentry nomor dan quantity work order. Program menyimpannya di akhir file (append). Listing 150. Append Work Order — append.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
Baris 10 sampai 13: jika anggota array work order telah mencapai maksimum maka fungsi segera berakhir. Baris 15: menyalin nilai count sebagai nomor index record lalu mengincrement count. Baris 16: memungut pointer data work order pada index idx. Baris 19: menanti pengguna mengentry nomor work order. Baris 21 dan 22: membuang newline di akhir nomor work order. Baris 24: mengclear buffer, memastikan tidak ada sisa karakter input. Baris 27: menanti pengguna mengentry quantity work order. Baris 28: mengclear buffer, memastikan tidak ada sisa karakter input.
59.5
Edit
Linux System Programming in C
224
Datatrans Informatika
Pengguna mengentry nomor index record (mulai dari 1), program menampilkan nomor dan quantity work order sesuai index tersebut. Lalu pengguna mengentry nomor dan quantity work order untuk mengupdate record pada index yang telah ditentukan. Listing 151. Edit Work Order — edit.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
#include #include <stdio.h> #include <string.h> void woedit(wo_arr* parr) { int idx, len; wo* pwo; if(parr->count < 1){ printf("no records available\n"); return; } printf("record number [1 to %d]: ", parr->count); scanf("%d", &idx); while ( getchar() != '\n' );//clear stdin if(idx<1 || idx > parr->count) { printf("invalid record number %d\n", idx); return; } pwo=parr->data+(idx-1); printf("WO Number: %s\n", pwo->no); printf("WO Qty: %d\n", pwo->qty); printf("WO Number: "); fgets(pwo->no, WO_NO_LEN+1, stdin); len=strlen(pwo->no); if(pwo->no[len-1]=='\n') pwo->no[len-1]=0; else while ( getchar() != '\n' );//clear stdin printf("Qty: "); scanf("%d", &pwo->qty); while ( getchar() != '\n' );//clear stdin return; }
Baris 9 sampai 12: jika tidak ada data work order, fungsi segera berakhir. Baris 15: menanti pengguna mengentry nomor index record (mulai dari 1). Baris 18 sampai 21: jika nomor index di luar jangkauan, fungsi segera berakhir. Baris 23: memungut pointer data work order pada sesuai index. Baris 24 dan 25: menampilkan nomor dan quantity work order. Baris 28: menanti pengguna mengentry nomor work order. Baris 30 dan 31: membuang newline di akhir nomor work order. Baris 36: menanti pengguna mengentry quantity work order.
Linux System Programming in C
225
Datatrans Informatika
59.6
Main
Berikut ini adalah main function sebagai central point: Listing 152. Main — mmap.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
while(!quit) { printf("R (read), A (append), E (edit), Q (quit): "); scanf("%c", &ch); while ( getchar() != '\n' );//clear stdin ch=tolower(ch); switch(ch) { case 'r': woread(parr); break; case 'a': woappend(parr); break; case 'e': woedit(parr); break; case 'q': quit=TRUE; break; default: printf("invalid option %c\n", ch); break; } } munmap(map, datasize); return 0; }
Baris 25: mengopen file test.dat. File dicreate jika tidak eksis. Baris 29: memungut informasi file. Hasilnya disimpan dalam fs bertipe struct stat. Baris 34 sampai 40: ukuran file dipastikan sesuai ukuran struktur data wo_arr. Baris 42: memap file ke dalam virtual address space program. Memori dialokasikan sebesar datasize byte. Sistem operasi secara otomatik menggenapkannya naik ke kelipatan pagseize. Proteksi diset PROT_READ|PROT_WRITE berarti area memori dapat diread maupun write. Flag MAP_SHARED berarti perubahan data di memori disimpan ke dalam file dan visible bagi proses lain yang tengah memap area file yang sama. Dengan demikian, perubahan data dalam fungsi woappend dan woedit otomatik disimpan ke dalam file test.dat. Baris 53: jika mmap berhasil maka fd boleh diclose. Baris 55: menampilkan nomor proses dan alamat memory mapped file. Baris 59 sampai 81: pengguna memilih aktivitas read, append, edit atau quit. Baris 83: jika pengguna memilih quit maka memory mapped file dihentikan.
59.7
Makefile
Guna memudahkan maintenance program, mari membuat Makefile: Listing 153. Makefile 1 2 3 4
.PHONY: all clean OBJS=mmap.o read.o edit.o append.o all: mmap
Terlebih dahulu mari memeriksa lokasi memory mapped file dalam virtual address space program: % ./mmap pid 8543, address mmap 0x7f01533a9000 R (read), A (append), E (edit), Q (quit):
Perhatikan alamat memory mapped file dalam virtual address space program. Alokasi digenapkan naik ke pagesize 4096 byte (heksadesimal 7f01533aa00016 – 7f01533a900016 = 100016 = 4096). Kembali ke terminal program mmap, ketik Q untuk mengakhiri program.
59.9
Menguji Interprocess Communication
Kali ini mari menguji mmap untuk interprocess communication. Buka 2 terminal bersebelahan. Dalam kedua terminal, launch mmap. % ./mmap pid 8904, address mmap 0x7f915d842000 R (read), A (append), E (edit), Q (quit):A WO Number: WHT100 Qty: 100 R (read), A (append), E (edit), Q (quit):
% ./mmap pid 8905, address mmap 0x7f278f1e6000 R (read), A (append), E (edit), Q (quit):
R record number [1 to 1]: WO Number: WHT100 WO Qty: 100 R (read), A (append), E (quit):E record number [1 to 1]: WO Number: WHT100 WO Qty: 100 WO Number: WHT101 Qty: 101 R (read), A (append), E (quit): R record number [1 to 1]: 1 WO Number: WHT101 WO Qty: 101 R (read), A (append), E (edit), Q (quit):Q
1 (edit), Q 1
(edit), Q
Q
Perhatikan, perubahan data oleh proses di terminal kiri juga dapat diamati oleh proses di terminal kanan (interprocess communication). Mari memeriksa isi file test.dat: % od -tx1c test.dat 0000000 01 00 00 00 001 \0 \0 \0 0000020 00 00 00 00 \0 \0 \0 \0 * 0002260 00 00 00 00 \0 \0 \0 \0 0002264
57 W 00 \0
48 H 00 \0
54 T 00 \0
31 1 00 \0
30 0 00 \0
31 1 00 \0
00 \0 00 \0
00 \0 00 \0
65 e 00 \0
00 \0 00 \0
00 \0 00 \0
00 \0 00 \0
Kesimpulan 1. Memory mapped file memetakan file ke virtual address space program. 2. Jika memory mapped file menggunakan flag MAP_SHARED maka setiap update data di memori akan direkam ke dalam file. Perubahan tersebut juga visible bagi proses lain yang tengah memap file yang sama. Tugas Eksplorasi 1. Diskusikan keuntungan dan kerugian merekam data ke dalam file antara memory mappedfile dan I/O library (open, write, close). Linux System Programming in C
229
Datatrans Informatika
2. Pada latihan sebelumnya kita telah membahas recordlevel file locking28. Coba terapkan pada fungsi woedit dan woappend guna mencegah race condition jika lebih dari satu proses mengupdate record pada index yang sama.
28 Lihat halaman 196. Linux System Programming in C
230
Datatrans Informatika
60 Unix Domain Socket
Tujuan Dapat menggunakan unix domain socket untuk komunikasi antar proses. Pada latihan sebelumnya kita telah mengeksplorasi penggunaan FIFO 29. FIFO menyediakan saluran komunikasi antar proses satu arah. Untuk sebuah saluran FIFO, suatu proses hanya dapat mengirim data dan proses lain menerimanya. Kali ini kita akan mempelajari penggunaan socket. Berbeda dengan FIFO, socket dapat digunakan sebagai saluran komunikasi dua arah. Socket dapat digunakan untuk komunikasi antar proses dalam sebuah komputer maupun berbeda komputer melalui saluran network. Bab ini membahas pemrograman unix domain socket untuk komunikasi antar proses dalam komputer bersistem operasi Linux. Sebuah proses bertindak sebagai server. Proses lain sebagai client. Agar dapat berkomunikasi, server diberi alamat tertentu. Selanjutnya client menghubungi server menggunakan alamat tersebut. Dalam unix domain socket, alamat socket adalah inode sebuah file. Berikut ini adalah singkronisasi server dan client dalam komunikasi menggunakan socket30: server socket
client socket
bind
listen
accept
read
write
close
connect
write
read
close
Gambar 16: Komunikasi Antar Proses Menggunakan Socket • • • • • • • •
Socket: create a new communication endpoint. Bind: attach a local address to a socket. Listen: announce willingness to accept connections. Accept: block caller until a connection request arrives. Connect: actively attempt to establish a connection. Send: send some data over the connection. Receive: receive some data over the connection. Close: release the connection.
29 Lihat halaman 191. 30 Lihat http://www.cs.iit.edu/~iraicu/teaching/CS550-S11/lecture08.pdf halaman 12 dan 13. Linux System Programming in C
231
Datatrans Informatika
60.1
Header
Mari membuat header untuk mendefinisikan path yang akan digunakan sebagai alamat socket. Listing 154. Header untuk Unix Socket — sock.h 1 2 3 4 5 6
Baris 19: mengcreate endpoint komunikasi dan menghasilkan descriptor yang disimpan dalam variabel sock_server. Argumen AF_UNIX menunjukkan bahwa socket akan digunakan untuk komunikasi lokal. Argumen SOCK_STREAM menunjukkan bahwa aliran data akan berlangsung dua arah, reliable, berupa byte stream (tidak dibatasi message boundary) dan berbasis koneksi (data hanya dapat dialirkan jika server dan client terkoneksi). Baris 27: menghapus file socket jika eksis. Jika tidak dihapus maka bind (baris 29) akan gagal dengan pesan error Address already in use. Baris 29: mengattach local adress ke socket. Baris 34: menjadikan sock_server sebagai penerima incoming connection dengan maksimum 5 antrian.
Linux System Programming in C
233
Datatrans Informatika
Baris 41: menanti dan merespons connection request yang mengantri di sock_server, meng create socket baru dan menghasilkan file descriptor yang disimpan ke dalam sock_client. Baris 46: memproses incoming connection dan melayani komunikasi data dengan client. Baris 62: menanti data dari client. Baris 72: mengirimkan data ke client. Membuild program: %
Baris 23: mengcreate endpoint komunikasi dan menghasilkan descriptor yang disimpan dalam variabel sock_client. Baris 32: mengestablish koneksi antara sock_client dengan server yang ditetapkan dalam variabel remote berstruktur data sockaddr_un. Baris 46: mengirimkan data ke server. Baris 53: menanti data dari server. Membuild program: %
gcc -o client -Wall client.c -I.
60.4
Mengujicoba Socket
Bukalah dua terminal bersebelahan. Sebelah kiri untuk melaunch server. Sebelah kanan untuk client. %
./server
% ./client message (exit to quit): test1234
from client: test1234 echo from server: test1234 message (exit to quit): exit from client: exit echo from server: exit ^C
Server dihentikan dengan CTRL+C. Kesimpulan Berdeda dengan pipe, socket menyediakan saluran komunikasi dua arah. Linux System Programming in C
235
Datatrans Informatika
Tugas Eksplorasi 1. Server dihentikan seketika dengan CTRL+C. Perbaikilah program agar diterminate dengan benar (mengindari memory leakage). 2. Saat ini server hanya dapat melayani satu client. Agar dapat melayani beberapa client secara serentak: 1) ubahlah menjadi program multithread dan 2) ubahlah program menjadi multiproses (menggunakan fork).
Linux System Programming in C
236
Datatrans Informatika
61 TCP/IP Socket
Tujuan Dapat menggunakan TCP/IP socket untuk komunikasi antar proses melalui jaringan komputer. Pada latihan sebelumnya kita telah mengeksplorasi komunikasi antar proses dalam satu komputer menggunakan unix domain socket. Kali ini kita akan berlatih menggunakan TCP/IP Socket untuk komunikasi antar proses melalui jaringan komputer. Berbeda dengan unix domain socket, TCP/IP socket dibinding dengan alamat IP dan nomor port.
Baris 18: alamat dideklarasikan dengan tipe struktur sockaddr_in. Struktur tersebut memiliki field address dan port. Baris 25: mengcreate endpoint komunikasi dan menghasilkan descriptor yang disimpan dalam variabel sock_server. Argumen AF_INET menunjukkan bahwa socket akan digunakan untuk komunikasi melalui jaringan. Argumen SOCK_STREAM menunjukkan bahwa aliran data akan berlangsung dua arah, reliable, berupa byte stream dan berbasis koneksi (data hanya dapat dialirkan jika server dan client terkoneksi). Baris 31 sampai 34: addrlocal diisi spesifikasi alamat server. Port dan address masing masing diset melalui htons dan htonl. Kedua fungsi tersebut memastikan port dan address diisi dalam format bigendian. Port diset ke nomor 9090. Address INADDR_ANY berarti socket dapat menerima incoming request melalui sembarang address network interface yang dimiliki komputer. Baris 36: menetapkan opsi untuk sock_server agar dapat menggunakan ulang address lokal untuk binding. Ketika suatu socket diclose, kernel Linux membutuhkan waktu untuk me release sumber daya socket terebut. Jika sumber daya belum selesai direlease, tanpa opsi SO_REUSEADDR, setiap binding socket ke address dan port yang sama akan menghasilkan error Address already in use. Baris 39: membinding address dan port bagi sock_server. Baris 47: menjadikan sock_server sebagai penerima incoming connection dengan maksimum 5 antrian. Baris 55: menanti dan merespons connection request yang mengantri di sock_server, meng create socket baru dan menghasilkan file descriptor yang disimpan ke dalam sock_client. Baris 65: mengkonversi address incoming request menjadi string. Baris 66: mengkonversi port incoming request yang semula berformat bigendian menjadi format komputer lokal. Baris 71: memproses incoming connection dan melayani komunikasi data dengan client. Baris 90: menanti data dari client. Baris 104: mengirimkan data ke client. Membuild program: %
printf("echo from server: "); waitserver=1; while(waitserver) { len=read(sock_client, buf, BUFSIZE); if(len<1) break; for(i=0;i
Baris 16: alamat dideklarasikan dengan tipe struktur sockaddr_in. Struktur tersebut memiliki field address dan port. Baris 22: mengcreate endpoint komunikasi dan menghasilkan descriptor yang disimpan dalam variabel sock_client. Argumen AF_INET menunjukkan bahwa socket akan digunakan untuk komunikasi melalui jaringan. Argumen SOCK_STREAM menunjukkan bahwa aliran data akan berlangsung dua arah, reliable, berupa byte stream dan berbasis koneksi (data hanya dapat dialirkan jika server dan client terkoneksi). Baris 28 sampai 30: addrlocal diisi spesifikasi alamat client. Port untuk client diset 0 berarti akan diisi secara otomatik oleh kernel Linux menggunakan nomor port lebih besar dari 1024 yang belum digunakan. Address INADDR_ANY berarti socket dapat mengirim connection request melalui sembarang address network interface yang dimiliki komputer. Baris 32: membinding address dan port bagi sock_client. Baris 40 sampai 42: addrserver diisi spesifikasi alamat server. Port diset melalui htons guna memastikan format bigendian. Address dikonversi dari string “127.0.0.1 ” menjadi struktur network address menggunakan fungsi inet_pton. Baris 43: mengestablish koneksi antara sock_client dengan server yang ditetapkan dalam variabel addrsever berstruktur data sockaddr_in. Baris 57: mengirimkan data ke server. Baris 64: menanti data dari server. Membuild program: %
gcc -o client -Wall client.c -I.
61.3
Mengujicoba Socket
Bukalah dua terminal bersebelahan. Sebelah kiri untuk melaunch server. Sebelah kanan untuk client. %
./server
Linux System Programming in C
241
Datatrans Informatika
wait client incoming connection
%
./client
incoming connection detected 127.0.0.1:37006
message (exit to quit):test1234
test1234 from client: exit
echo from server: test1234 message (exit to quit): exit
wait client incoming connection ^C
Server dihentikan dengan CTRL+C. Kesimpulan TCP/IP socket menyediakan saluran komunikasi dua arah antar komputer melalui jaringan. Tugas Eksplorasi 1. Program latihan di atas menggunakan IP address untuk alamat server. Gunakan getaddrinfo agar alamat server dapat ditentukan menggunakan host name. 2. Server dihentikan seketika dengan CTRL+C. Perbaikilah program agar diterminate dengan benar (mengindari memory leakage). 3. Saat ini server hanya dapat melayani satu client. Agar dapat melayani beberapa client secara serentak: 1) ubahlah menjadi program multithread dan 2) ubahlah program menjadi multiproses (menggunakan fork).
Linux System Programming in C
242
Datatrans Informatika
XV PostgreSQL Stored Procedure Programming
62 Operasi Bilangan 63 Operasi Text 64 Mendrive Perangkat Keras 65 Set Returning Function 66 Server Programming Interface
Linux System Programming in C
243
Datatrans Informatika
62 Operasi Bilangan
Tujuan Dapat membuat stored procedure server database PostgreSQL menggunakan bahasa pemrograman C untuk operasi bilangan. Server database PostgreSQL menyediakan pilihan pemrograman stored procedure dalam bahasa C. Kita akan mencoba membuatnya untuk operasi bilangan sederhana, penjumlahan 3 bilangan bertipe smallint, integer dan double.
Baris 1 sampai 2: menginclude header untuk membuild stored procedure PostgreSQL. Baris 4 sampai 6: sejak PostgreSQL versi 8.2, kode C harus menginclude magic block guna pemeriksaan kompatibilitas modul yang dikompilasi dengan versi PostgreSQL berbeda. Linux System Programming in C
244
Datatrans Informatika
Baris 8 dan 9: deklarasi fungsi mysum. PostgreSQL menggunakan tipe data abstrak Datum untuk menerima argumen maupun mereturn nilai. Tipe data ini dijelaskan secara detail dalam header postgres.h. Baris 16 dan 17: memastikan 3 argumen. Jika tidak maka fungsi akan menerbitkan pesan error please specify 3 numbers. Baris 19 dan 20: memastikan tidak ada argumen yang NULL. Jika tidak maka fungsi akan menerbitkan pesan error NULL arguments. Baris 22: memungut argumen pertama. Makro PG_GETARG_INT16 mengkonversi Datum ke tipe int16. Baris 23: memungut argumen kedua. Makro PG_GETARG_INT32 mengkonversi Datum ke tipe int32. Baris 24: memungut argumen kedua. Makro PG_GETARG_FLOAT8 mengkonversi Datum ke tipe float8. Baris 26 dan 27: mengakumulasi semua bilangan ke dalam variabel num3. Baris 29: mereturn akumulasi bilangan. Makro PG_RETURN_FLOAT8 mengkonversi float8 ke tipe Datum dan mereturnnya.
62.2
File SQL untuk Instalasi
Mari mempersiapkan 2 file sql untuk instalasi dan uninstall. Listing 160. File Instalasi — mymodule.sql.in 1 2 3
CREATE OR REPLACE FUNCTION mysum(IN num1 smallint, IN num2 integer, IN sum3 float8) RETURNS float8 AS 'MODULE_PATHNAME', 'mysum' LANGUAGE C IMMUTABLE;
Baris 1: nama modul c. Modul kita akan dibuild menjadi shared object bernama mymodule.so. Baris 5: lokasi executable file pg_config. Sesuaikan dengan instalasi server database PostgreSQL di komputer anda.
62.4
Build dan Instalasi
Linux System Programming in C
245
Datatrans Informatika
Pastikan berada dalam direktori Makefile, mari membuild modul:
Perhatikan, kita memperoleh 3 file baru: mymdoule.so, mymdoule.sql (dicreate dari mymodule.sql.in) dan mymoduleuninstall.sql (dicreate dari mymoduleuninstall.sql.in). Menginstalasi modul (pastikan anda memiliki privilege root):
Menginstalasi stored procedure ke database training (pastikan anda telah menstart server databaes PostgreSQL dan mengcreate database tersebut): %
/opt/pgsql/training/bin/psql -U postgres -h 127.0.0.1 -p 5432 -d training -f mymodule.sql Password for user postgres: CREATE FUNCTION
62.5
Mengujicoba Stored Procedure
Login ke server database:
% /opt/pgsql/training/bin/psql -U postgres -h 127.0.0.1 -p 5432 -d training Password for user postgres: psql (9.3.4) Type "help" for help. Training=# \timing on Timing is on. Training=# select mysum(1::smallint, 2, 3.1); mysum ------6.1 (1 row) Time: 0.493 ms training=# \q
Perhatikan kita memperoleh hasil penjumlahan yang benar (6.1). Kesimpulan 1. Kita dapat membuat stored procedure PostgreSQL dalam bahasa C. 2. Extension Building Infrastructure membantu mempermudah build dan instalasi modul.
Linux System Programming in C
246
Datatrans Informatika
63 Operasi Text
Tujuan Dapat membuat stored procedure server database PostgreSQL menggunakan bahasa pemrograman C untuk operasi text. Pada latihan sebelumnya kita telah membuat modul C untuk stored procedure server database PostgreSQL. Kali ini kita akan menambah fungsionalitas modul tersebut dengan operasi text. Yaitu, fungsi untuk menghitung banyaknya vokal dalam kalimat. Lalu kita akan membandingkan kinerjanya dengan fungsi yang sama dalam bahasa PLPGSQL.
#include <postgres.h> #include #include PG_FUNCTION_INFO_V1(myvocalcount); Datum myvocalcount(PG_FUNCTION_ARGS); Datum myvocalcount(PG_FUNCTION_ARGS) { int32 argcount; text* t; char* s; int32 count=0; argcount=PG_NARGS(); if(argcount!=1) elog(ERROR, "1 arguments expected"); if( PG_ARGISNULL(0) ) elog(ERROR, "NULL argument"); t=PG_GETARG_TEXT_PP(0); s=text_to_cstring(t); while(*s) { switch( *(s++) ) { case 'a': case 'A': case 'i': case 'I': case 'u': case 'U': case 'e': case 'E': case 'o':
Linux System Programming in C
247
Datatrans Informatika
34 35 36 37 38 39 40 41 42 43
case 'O': count++; break; default: break; } } PG_RETURN_INT32(count); }
Baris 21: memungut argumen. Makro PG_GETARG_TEXT_PP mengkonversi Datum ke tipe text*. Baris 22: mengkonversi tipe text* menjadi char* sehingga kita dapat menggunakan library C untuk memproses string. Baris 23 sampai 40: menghitung banyaknya vokal dalam kalimat. Baris 42: mereturn count. Makro PG_RETURN_INT32 mengkonversi int32 ke tipe Datum dan mereturnnya.
63.2
File SQL untuk Instalasi
Mari memodifikasi mymdoule.sql.in dan mymdouleuninstall.sql.in: Listing 164. File Instalasi — mymodule.sql.in 1 2 3 4 5 6 7
CREATE OR REPLACE FUNCTION mysum(IN num1 smallint, IN num2 integer, IN sum3 float8) RETURNS float8 AS 'MODULE_PATHNAME', 'mysum' LANGUAGE C IMMUTABLE; CREATE OR REPLACE FUNCTION myvocalcount(IN t text) RETURNS integer AS 'MODULE_PATHNAME', 'myvocalcount' LANGUAGE C IMMUTABLE;
Kita menambahkan baris 5 sampai 7. Listing 165. File Uninstall — mymoduleuninstall.sql.in 1 2
DROP FUNCTION mysum(IN num1 smallint, IN num2 integer, IN sum3 float8); DROP FUNCTION myvocalcount(IN t text);
Kita menambahkan baris 2.
63.3
Makefile
Mari memodifikasi Makefile untuk mencantumkan text.c dalam proses build. Listing 166. Makefile 1 2 3 4 5 6 7
Pastikan berada dalam direktori Makefile, mari menguninstall modul (pastikan anda memiliki privilege root): % make uninstall rm -f '/opt/pgsql/training/lib/mymodule.so' rm -f '/opt/pgsql/training/share/contrib'/mymodule.sql '/opt/pgsql/training/share/contrib'/mymodule-uninstall.sql
Menginstalasi stored procedure ke database training (pastikan anda telah menstart server databaes PostgreSQL dan mengcreate database tersebut): %
/opt/pgsql/training/bin/psql -U postgres -h 127.0.0.1 -p 5432 -d training -f mymodule.sql Password for user postgres: CREATE FUNCTION CREATE FUNCTION
63.5
Operasi Text dalam PLPGSQL
Sebagai pembanding kinerja modul C mari mempersiapkan stored procedure dalam bahasa PLPGSQL: Listing 167. Stored Procedure PLPGSQL — pl.sql 1 2
CREATE OR REPLACE FUNCTION vocalcount(IN t text) RETURNS integer AS
Linux System Programming in C
249
Datatrans Informatika
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
$BODY$ DECLARE _count integer:=0; _len integer; _i integer; _c text; BEGIN _len:=LENGTH(t); FOR _i IN 1.._len LOOP _c:=SUBSTR(t,_i,1); IF _c='a' OR _c='A' OR _c='i' OR _c='I' OR _c='u' OR _c='U' OR _c='e' OR _c='E' OR _c='o' OR _c='O' THEN _count:=_count+1; END IF; END LOOP; RETURN _count; END $BODY$ LANGUAGE plpgsql IMMUTABLE;
Menginstalasinya ke server database PostgreSQL: %
/opt/pgsql/training/bin/psql -U postgres -h 127.0.0.1 -p 5432 -d training -f pl.sql Password for user postgres: CREATE FUNCTION
63.6
Mengujicoba Stored Procedure
Persiapkan dua terminal bersebelahan. Sebelah kiri untuk mengexecute stored procedure dalam bahasa C. Sebelah kanan untuk versi PLPGSQL: %
/opt/pgsql/training/bin/psql -U postgres -h 127.0.0.1 -p 5432 -d training Password for user postgres: psql (9.3.4) Type "help" for help.
%
training=# \timing on Timing is on. training=# select myvocalcount('pt citra tubindo beralamat di kabil industrial estate memproduksi pipa gas dan minyak'); myvocalcount -------------29 (1 row)
training=# \timing on Timing is on. training=# select vocalcount('pt citra tubindo beralamat di kabil industrial estate memproduksi pipa gas dan minyak'); vocalcount -----------29 (1 row)
Time: 1.514 ms training=# select myvocalcount('pt citra tubindo beralamat di kabil industrial estate memproduksi pipa gas dan minyak'); myvocalcount -------------29 (1 row)
Time: 4.060 ms training=# select vocalcount('pt citra tubindo beralamat di kabil industrial estate memproduksi pipa gas dan minyak'); vocalcount -----------29 (1 row)
Time: 0.413 ms training=# select myvocalcount('pt
Time: 0.808 ms training=# select vocalcount('pt
Linux System Programming in C
/opt/pgsql/training/bin/psql -U postgres -h 127.0.0.1 -p 5432 -d training Password for user postgres: psql (9.3.4) Type "help" for help.
250
Datatrans Informatika
citra tubindo beralamat di kabil industrial estate memproduksi pipa gas dan minyak'); myvocalcount -------------29 (1 row)
citra tubindo beralamat di kabil industrial estate memproduksi pipa gas dan minyak'); vocalcount -----------29 (1 row)
Time: 0.376 ms training=# \q
Time: 0.794 ms training=# \q
Perhatikan pada execute pertama, kedua stored procedure membutuhkan waktu lebih lama dibandingkan execute kedua dan ketiga karena waktu ekstra untuk meloading modul ke memori pertama kali. Modul C lebih cepat dibandingkan PLPGSQL. Perbedaan tersebut makin drastis untuk text yang lebih panjang. Kesimpulan Untuk algoritma yang melibatkan looping, modul C lebih cepat dibandingkan PLPGSQL.
Linux System Programming in C
251
Datatrans Informatika
64 Mendrive Perangkat Keras
Tujuan Dapat membuat stored procedure server database PostgreSQL menggunakan bahasa pemrograman C untuk mendrive perangkat keras. Kita pernah mengeksplorasi parallel port untuk menyalakan dan memadamkan lampu LED31 melalui USB to parallel converter. Converter tersebut diattach ke sistem operasi melalui path /dev/usb/lp0. Kali ini kita akan mengoperasikannya melalui stored procedure server database PostgreSQL. Pada latihan sebelumnya kita telah membuat modul C untuk stored procedure server database PostgreSQL. Kali ini kita akan menambah fungsionalitas modul tersebut dengan operasi pengendalian perangkat keras.
64.1
Mengizinkan Access /dev/usb/lp0
Terlebih dahulu kita memastikan /dev/usb/lp0 dapat diakses oleh user selain root. Edit file /lib/udev/rules.d/50udevdefault.rules. Cari baris berisi teks: KERNEL=="lp[0-9]*", GROUP="lp"
Tambahkan MODE=”0666”:
KERNEL=="lp[0-9]*", GROUP="lp", MODE="0666"
Simpan perubahan tersebut.
64.2
Source Code
Listing 168. Operasi Perangkat Keras — lampu.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
CREATE OR REPLACE FUNCTION mysum(IN num1 smallint, IN num2 integer, IN sum3 float8) RETURNS float8 AS 'MODULE_PATHNAME', 'mysum' LANGUAGE C IMMUTABLE; CREATE OR REPLACE FUNCTION myvocalcount(IN t text) RETURNS integer AS 'MODULE_PATHNAME', 'myvocalcount' LANGUAGE C IMMUTABLE; CREATE OR REPLACE FUNCTION lampu(IN code smallint, IN port text) RETURNS void AS 'MODULE_PATHNAME', 'lampu' LANGUAGE C IMMUTABLE;
Kita menambahkan baris 9 sampai 10. Listing 170. File Uninstall — mymoduleuninstall.sql.in 1 2 3
DROP FUNCTION mysum(IN num1 smallint, IN num2 integer, IN sum3 float8); DROP FUNCTION myvocalcount(IN t text); DROP FUNCTION lampu(IN code smallint, IN port text);
Kita menambahkan baris 3.
64.4
Makefile
Mari memodifikasi Makefile untuk mencantumkan lampu.c dalam proses build. Listing 171. Makefile 1 2
Pastikan berada dalam direktori Makefile, mari menguninstall modul (pastikan anda memiliki privilege root): % make uninstall rm -f '/opt/pgsql/training/lib/mymodule.so' rm -f '/opt/pgsql/training/share/contrib'/mymodule.sql '/opt/pgsql/training/share/contrib'/mymodule-uninstall.sql
Menginstalasi stored procedure ke database training (pastikan anda telah menstart server databaes PostgreSQL dan mengcreate database tersebut): %
/opt/pgsql/training/bin/psql -U postgres -h 127.0.0.1 -p 5432 -d training
Linux System Programming in C
254
Datatrans Informatika
-f mymodule.sql Password for user postgres: CREATE FUNCTION CREATE FUNCTION CREATE FUNCTION
64.6
Mengujicoba Stored Procedure
Attach USB to parallel converter ke komputer anda. Login ke server database dan execute fungsi lampu: % /opt/pgsql/training/bin/psql -U postgres -h 127.0.0.1 -p 5432 -d training Password for user postgres: psql (9.3.4) Type "help" for help. training=# select lampu(10::smallint, '/dev/usb/lp0'); lampu ------(1 row) training=# \q
Perhatikan lampu menyala sesuai representasi biner kode. Kesimpulan 1. Stored procedure dalam bahasa C dapat digunakan untuk mendrive perangkat keras. 2. Pastikan user yang digunakan untuk menstart server postgresql memperoleh privilege untuk mengakses perangkat keras.
Linux System Programming in C
255
Datatrans Informatika
65 Set Returning Function
Tujuan Dapat membuat stored procedure server database PostgreSQL menggunakan bahasa pemrograman C untuk menghasilkan himpunan record. Kita telah berlatih membuat stored procedure dalam bahasa C untuk memproses beberapa input dan menghasilkan satu output. Kali ini kita akan berlatih membuat stored procedure untuk menghasilkan himpunan record. PostgreSQL menyebutnya sebagai Set Returning Function.
65.1
File Teks
Sebagai contoh, kita mempunyai sebuah file teks /opt/course/pgsql/srf/wo.txt berisi data Work Order (WO) dan quantitynya dibatasi titikkoma (;). Tiap baris diakhiri newline. % cat /opt/course/pgsql/srf/wo.txt WHT100;100 WHT200;200 WHT300;300 WHT400;400
Pastikan file tersebut dapat dibaca oleh other:
% chmod a+r /opt/course/pgsql/srf/wo.txt % ls /opt/course/pgsql/srf/wo.txt -l -rw-rw-r-- 1 abdul abdul 44 Dec 1 10:05 /opt/course/pgsql/srf/wo.txt
Baris 18: deklarasi variabel funcctx bertipe pointer FuncCallContext. Set returning function adalah fungsi yang dieksekusi secara multi call. Untuk setiap call, fungsi menghasilkan sebuah record. Multi call berakhir jika tidak ada lagi record yang dihasilkan. Datadata temporer untuk setiap call akan didestroy dari memori. Pointer funcctx menyimpan data yang harus survive selama multi call. Baris 29 dan 30: values dan isnull dideklarasikan sebagai array dengan 2 elemen. Array array ini digunakan untuk mempersiapkan record dengan 2 field: wo dan qty. Array values dan isnull masingmasing untuk menyimpan Datum nilai dan status NULL. Baris 34 sampai 59: blok kode untuk pemanggilan pertama. Baris 42: elemen tuple_desc berisi descriptor untuk fieldfield record yang akan dihasilkan. Baris 49 dan 50: memungut filepath dari argumen fungsi. Baris 52: mengopen file dengan mode reading. Baris 56: menyimpan pointer FILE* sebagai elemen user_fctx. Baris 61: setup untuk penggunaan FuncCallContext dan mengclear data yang dihasilkan pada call sebelumnya (untik multi call ke2 dan seterusnya). Baris 65: mengcasting user_fctx kembali ke FILE*. Baris 66: membaca isi file per baris. Baris 68 sampai 87: jika masih ada data dari file, fungsi menghasilkan record. Baris 89 sampai 91: jika tidak ada lagi data dari file, fungsi mengclose file dan mengakhiri multi call.
65.3
File SQL untuk Instalasi
Mari mempersiapkan 2 file sql untuk instalasi dan uninstall. Listing 173. File Instalasi — mysrf.sql.in 1 2 3
CREATE OR REPLACE FUNCTION readwo(IN path text, OUT wo text, OUT qty integer) RETURNS SETOF RECORD AS 'MODULE_PATHNAME', 'readwo' LANGUAGE C IMMUTABLE;
Menginstalasi stored procedure ke database training (pastikan anda telah menstart server databaes PostgreSQL dan mengcreate database tersebut): %
/opt/pgsql/training/bin/psql -U postgres -h 127.0.0.1 -p 5432 -d training -f mysrf.sql Password for user postgres: CREATE FUNCTION
65.6
Mengujicoba Stored Procedure
Login ke server database:
% /opt/pgsql/training/bin/psql -U postgres -h 127.0.0.1 -p 5432 -d training Password for user postgres: psql (9.3.4) Type "help" for help. training=# select * from readwo('/opt/course/pgsql/srf/wo.txt'); wo | qty --------+----WHT100 | 100 WHT200 | 200 WHT300 | 300 WHT400 | 400 (4 rows) training=# \q
Linux System Programming in C
259
Datatrans Informatika
Perhatikan kita memperoleh empat record yang berasal dari isi file wo.txt. Kesimpulan 1. Set Returning Function adalah stored procedure PostgreSQL yang menghasilkan himpunan record. 2. Himpunan record dihasilkan melalui multicall. 3. Adalah tugas programmer untuk menentukan akhir multicall.
Linux System Programming in C
260
Datatrans Informatika
66 Server Programming Interface
Tujuan Dapat membuat stored procedure server database PostgreSQL menggunakan bahasa pemrograman C untuk mengakses objekobjek database melalui Server Programming Interface. Kita telah mempelajari pemrograman C untuk membuat stored procedure server database PostgreSQL. Kali ini kita akan mempelajari penggunaan Server Programming Interface untuk mengakses objekobjek server database.
66.1
Tabel Work Order
Terlebih dahulu mari mempersiapkan tabel workorder dengan 2 field: 1) wonumber text NOT NULL dan 2) qty integer NOT NULL. Pastikan server database sudah distart dan anda memiliki database training. % /opt/pgsql/training/bin/psql -U postgres -h 127.0.0.1 -p 5432 -d training Password for user postgres: psql (9.3.4) Type "help" for help. training=# create table workorder(wonumber text NOT NULL, qty integer NOT NULL, constraint wo_pkey primary key (wonumber)) without oids; CREATE TABLE training=# \q
66.2
Source Code Insert Data
Berikut ini adalah source code untuk menginsert data ke dalam tabel workorder: Listing 176. Insert Data — insert.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
#include #include #include #include
<postgres.h> <executor/spi.h>
#ifdef PG_MODULE_MAGIC PG_MODULE_MAGIC; #endif PG_FUNCTION_INFO_V1(insertwo); Datum insertwo(PG_FUNCTION_ARGS); Datum insertwo(PG_FUNCTION_ARGS) { Datum values[2]; Oid oids[]={TEXTOID, INT4OID}; int status;
Baris 3: menginclude header untuk Server Programming Interface (SPI). Baris 15: Array objek id (OID) berisi id untuk text (TEXTOID) dan integer (INT4OID). Baris 28: memulai koneksi ke SPI manager agar selanjutnya dapat memanggil fungsifungsi SPI. Baris 30: memanggil fungsi SPI untuk mengeksekusi SQL berparameter: • Argumen pertama adalah perintah SQL berparameter. Parameter dimulai dengan simbol $1, $2 dan seterusnya. • Argumen kedua adalah banyaknya parameter. • Argumen ketiga adalah array objek id (OID) sesuai tipe data parameter. • Argumen keempat adalah array berisi Datum untuk parameter SQL. • Argumen kelima adalah array karakter untuk status NULL. Jika argumen ini diset NULL maka tidak ada satupun nilai parameter yang NULL. • Argumen keenam adalah flag bertipe boolean yang diset TRUE jika perintah SQL read only. • Argumen ketujuh adalah maksimum banyaknya record yang akan direturn. Jika diset 0 maka tidak ada limit.
66.3
File SQL untuk Instalasi
Mari mempersiapkan 2 file sql untuk instalasi dan uninstall. Listing 177. File Instalasi — myspi.sql.in 1 2 3
CREATE OR REPLACE FUNCTION insertwo(IN wo text, IN qty integer) RETURNS void AS 'MODULE_PATHNAME', 'insertwo' LANGUAGE C VOLATILE;
Perhatikan kita telah menginsert sebuah record ke dalam tabel workorder menggunakan Server Programming Interface. Kesimpulan Dalam stored proceduer berbahasa C kita dapat mengakses objekobjek database PostgreSQL menggunakan Server Programming Interface. Tugas Eksplorasi 1. Buatlah fungsi untuk mengupdate dan mendelete record workorder menggunakan Server Programming Interface. 2. Buatlah set returning function untuk mengquery record dari tabel workorder.
Linux System Programming in C
264
Datatrans Informatika
XVI Web Driven Linux Resources Programming
67 Menginvoke Fungsi Shared Library 68 Javascript Callback 69 Mozilla Addon SDK
Linux System Programming in C
265
Datatrans Informatika
67 Menginvoke Fungsi Shared Library
Tujuan Dapat menginvoke fungsi dalam shared library melalui kode javascript menggunakan js ctypes. Sejak versi 5, browser Firefox menyediakan library jsctypes yang digunakan untuk meng invoke fungsi dalam shared library melalui kode javascript. Kita akan berlatih mengatur nyala lampu LED melalui USB to Parellel Port Converter 32. Kali ini melalui kode javascript halaman web. Gunakan browser Firefox antara versi 5 sampai 14. Komunikasi antara HTML, javascript dan shared library adalah sebagai berikut: client browser
http request
loaded from web server HTML
web server javascript
HTML
respons: HTML javascript
javascript jsctypes installed locally mylib.so
LED
Gambar 17: Komunikasi antara Javascript dan mylib.so
67.1
Shared Library
Terlebih dahulu kita membuat shared library berisi kode untuk mengendalikan nyala lampu LED. Listing 180. Source Code Shared Library — mylib.c 1 2 3
Baris 6: atur sesuai access path USB to parallel converter di komputer anda. Pastikan path tersebut dapat diakses oleh nonroot user 33. Listing 181. Makefile 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
Baris 1 sampai 5: menentukan path instalasi mylib.so. Untuk arsitektur 64 bit, mylib.so akan diinstalasi di direktori /usr/lib64/. Untuk 32 bit di /usr/lib. Baris 15: rule install menyalib mylib.so ke direktori library sesuai arsitektur operating system dengan permission rwxrxrx. Baris 16: rule uninstall menghapus mylib.so dari direktori library. Membuild shared library:
Jika berhasil, kita memperoleh shared library mylib.so. Menginstalasi shared library (lakukan dengan privilege root): % make install install -m 0755
67.2
mylib.so /usr/lib64
Kode Javascript
Mari mempersiapkan file berisi kode javascript yang akan dilink ke halaman HTML. Listing 182. Source Code Javascript — mylib.js 1 2
var ctypes_loaded=false;
33 Lihat halaman 252. Linux System Programming in C
267
Datatrans Informatika
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
function load_ctypes() { if(!ctypes_loaded) { netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect") ; Components.utils.import("resource://gre/modules/ctypes.jsm"); ctypes_loaded=true; } } function led(d) { var libc = ctypes.open("mylib.so"); var func = libc.declare( "led", ctypes.default_abi, ctypes.void_t, ctypes.uint8_t); func(d); libc.close(); }
Baris 1: deklarasi variabel ctypes_loaded sebagai flag guna memastikan library jsctypes di load hanya sekali dalam fungsi load_ctypes(). Baris 3 sampai 9: fungsi load_ctypes untuk meload library jsctypes. Baris 11 sampai 20: menginvoke fungsi led di dalam shared library mylib.so. Baris 12: meload shared library. Atur path mylib.so sesuai instalasi di komputer anda. Baris 13: mendeklarasikan fungsi dalam mylib.so menggunakan: • Argumen pertama led adalah nama fungsi di dalam shared library. • Argumen kedua ctypes.default_abi adalah calling convention fungsi34. • Argumen ketiga ctypes.void_t adalah return type fungsi yang berpadanan dengan void dalam bahasa c35. • Argumen keempat ctypes.uint8_t adalah tipe argumen fungsi yang berpadanan dengan unsigned char dalam bahasa c36. Baris 18: menginvoke fungsi dalam shared library. Baris 19: mengclose shared library.
67.3
HTML
Berikut ini adalah file HTML yang akan diload ke dalam browser Firefox: Listing 183. HTML — index.html 1 2 3 4 5 6 7 8
<meta http-equiv="content-type" content="text/html; charset=utf8" /> hardware access <script type="text/javascript" src="mylib.js"> <script type="text/javascript"> function ledClick() { var s = document.getElementById('leddata').value;
34 Lihat https://developer.mozilla.org/en-US/docs/Mozilla/js-ctypes/js-ctypes_reference/ctypes#ABI_constants. 35 Lihat https://developer.mozilla.org/en-US/docs/Mozilla/js-ctypes/jsctypes_reference/ctypes#Special_C_types. 36 Lihat https://developer.mozilla.org/en-US/docs/Mozilla/js-ctypes/js-ctypes_reference/ctypes#Primitive_types. Linux System Programming in C
268
Datatrans Informatika
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
67.4
var d = parseInt(s, 10); d = isNaN(d) ? 0 : d; led(d); }
Deploy
Salin file index.html dan mylib.js ke root folder server web. Misalnya, untuk server web Tomcat, create direktori mylib dalam root folder /var/lib/tomcat/webapps. Lalu salin kedua file ke dalam /var/lib/tomcat/webapps/mylib. Restart server web tomcat.
67.5
Mengujicoba
Kode javascript hanya valid untuk browser Firefox versi 5 sampai 14. Launch browser. Ketik URL http://127.0.0.1:8080/mylib/index.html.
Gambar 18: Halaman Web Terdapat 3 objek: • Tombol Load jsctypes untuk meload library jsctypes. • Editor teks untuk mengisi kode nyala lampu LED. • Tombol Lampu untuk mentrigger nyala lampu LED.
67.5.1 Meload Library jsctypes Klik tombol Load jsctypes. Anda harus merespons dialog box:
Linux System Programming in C
269
Datatrans Informatika
Gambar 19: Privilege JsCtypes Beri tanda cek dalam box Remember this descision. Lalu klik tombol Allow.
67.5.2 Mengatur Nyala Lampu Persiapkan USB to parallel converter yang terhubung ke rangkaian LED. Plug converter ke dalam port USB komputer. Isi angka antara 0 sampai 255 dalam editor teks. Lalu klik tombol Lampu. Kesimpulan Library jsctypes digunakan untuk menginvoke fungsi dalam shared library melalui kode javascript.
Linux System Programming in C
270
Datatrans Informatika
68 Javascript Callback
Tujuan Dapat memprogram kode callback javascript yang akan dipanggil dari dalam shared library. Pada latihan sebelumnya kita telah berhasil memanggil kode shared library dari javascript. Kali ini kita mencoba sebaliknya, memanggil kode javacript dari dalam shared library. Misalnya, kode javacript memerintahkan fungsi dalam shared library untuk membaca file teks. Selanjutnya, untuk setiap baris data yang dibaca dari file teks, shared library menginvoke fungsi javascript untuk menampilkan data ke halaman web. Fungsi javascript yang akan dipanggil dari dalam shared library diimplementasikan berupa callback function. client browser installed locally
loaded from web server
mylib.so
jsctypes
read file teks data data data
http request
javascript
HTML
web server javascript HTML
respons: HTML javascript
javascript callback function
Gambar 20: Komunikasi antara mylib.so dan Callback Javascript Kita akan memodifikasi 3 file latihan sebelumnya: mylib.c, mylib.js dan index.html. Sedangkan Makefile tidak berubah.
Baris 18 sampai 46: fungsi untuk membaca file teks. Argumen pertama adalah path file teks. Argumen kedua adalah callback function yang diinvoke pada baris 42. Fungsi harus memenuhi syarat deklarasi: void fungsi(const char*, int)
• Return type void. • Argumen pertama adalah string (const char*) untuk nomor workorder. • Argumen kedua adalah integer (int) untuk quantity. Membuild shared library:
if(!ctypes_loaded) { netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect") ; Components.utils.import("resource://gre/modules/ctypes.jsm"); ctypes_loaded=true; } } function led(d) { var libc = ctypes.open("mylib.so"); var func = libc.declare( "led", ctypes.default_abi, ctypes.void_t, ctypes.uint8_t); func(d); libc.close(); } function callbackWo(wonum, qty) { var span1 = document.createElement('span'); span1.innerHTML=wonum.readString().concat(' '); var span2 = document.createElement('span'); span2.innerHTML=qty; var div = document.createElement('div'); div.appendChild(span1); div.appendChild(span2); var d = document.getElementById('data'); d.appendChild(div); } function readwo(filepath) { var d = document.getElementById('data'); while (d.firstChild) { d.removeChild(d.firstChild); } var callbackType = ctypes.FunctionType( ctypes.default_abi, ctypes.void_t, [ctypes.char.ptr, ctypes.int32_t] ).ptr; var callback_fn=callbackType(callbackWo); var libc = ctypes.open("mylib.so"); var func = libc.declare("readwo", ctypes.default_abi, ctypes.void_t, ctypes.char.ptr, ctypes.voidptr_t ); func(filepath, callback_fn); libc.close(); }
Baris 22 sampai 33: callback function yang akan dipanggil dari dalam shared library37. Baris 35 sampai 56: fungsi untuk membaca file teks. 37 Deklarasi fungsi harus cocok dengan syarat callback function dalam shared library, lihat halaman 272. Linux System Programming in C
273
Datatrans Informatika
Baris 41 sampai 45: mengcreate pointer tipe callback function: • Argumen pertama: ctypes.default_abi adalah calling convention fungsi38. • Argumen kedua ctypes.void_t adalah return type fungsi yang berpadanan dengan void dalam bahasa c. • Argumen ketiga ctypes.voidptr_t adalah tipe argumen untuk callback function. Baris 47: Mengcreate objek callback function menggunakan. Perhatikan fungsi callbackWo disuplai sebagai argumen. Baris 49: meload shared library. Atur path mylib.so sesuai instalasi di komputer anda. Baris 50: mendeklarasikan fungsi dalam mylib.so menggunakan: • Argumen pertama readwo adalah nama fungsi di dalam shared library. • Argumen kedua ctypes.default_abi adalah calling convention fungsi39. • Argumen ketiga ctypes.void_t adalah return type fungsi yang berpadanan dengan void dalam bahasa c40. • Argumen keempat ctypes.char.ptr adalah tipe argumen untuk path file teks. • Argumen kelima ctypes.voidptr_t adalah tipe argumen untuk callback function. Baris 55: menginvoke fungsi dalam shared library. Baris 56: mengclose shared library.
68.3
HTML
Mari memodifikasi file HTML yang akan diload ke dalam browser Firefox: Listing 186. HTML — index.html 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
<meta http-equiv="content-type" content="text/html; charset=utf8" /> hardware access <script type="text/javascript" src="mylib.js"> <script type="text/javascript"> function ledClick() { var s = document.getElementById('leddata').value; var d = parseInt(s, 10); d = isNaN(d) ? 0 : d; led(d); } function woClick() { var s = document.getElementById('file').value; readwo(s); }
38 Lihat https://developer.mozilla.org/en-US/docs/Mozilla/js-ctypes/js-ctypes_reference/ctypes#ABI_constants. 39 Lihat https://developer.mozilla.org/en-US/docs/Mozilla/js-ctypes/js-ctypes_reference/ctypes#ABI_constants. 40 Lihat https://developer.mozilla.org/en-US/docs/Mozilla/js-ctypes/jsctypes_reference/ctypes#Special_C_types. Linux System Programming in C
274
Datatrans Informatika
27 28 29 30
Baris 26: menampilkan editor teks untuk mengisi path file teks. Baris 27: menampilkan tombol WO. Baris 23: mempersiapkan node dengan id data sebagai tempat untuk menampilkan baris baris data file teks.
Gambar 21: Halaman Web Klik tombol Load jsctypes untuk meload library jsctypes. Isi path file teks, misalnya /opt/course/wo.txt. Lalu klik tombol WO. Perhatikan, barisbaris workorder dalam file teks wo.txt ditampilkan di halaman web. Kesimpulan Library jsctypes dapat digunakan untuk menginvoke callback function javascript dari dalam shared library.
Linux System Programming in C
275
Datatrans Informatika
69 Mozilla Addon SDK
Tujuan Dapat membuat addon Firefox menggunakan Mozilla Addon SDK untuk implementasi js ctypes. Pada latihan sebelumnya kita telah membuild shared library mylib.so. Fungsifungsi di dalamnya berinteraksi dengan javascript melalui library jsctypes. Karena alasan security, sejak versi 16 firefox menghentikan fungsi javascript netscape.security.PrivilegeManager.enablePrivilege. Library jsctypes masih dapat diimplentasikan melalui addon firefox (dikemas dalam paket file berekstensi *.xpi). Pada latihan kali ini kita akan membuat paket Addon bernama myaddon.xpi.
69.1
Instalasi Mozilla Addon SDK
Guna memudahkan pengemasan addon, mozilla menyediakan Addon SDK 41. • Paket instalasi dapat diunduh menggunakan link https://ftp.mozilla.org/pub/mozilla.org/labs/jetpack/jetpacksdklatest.tar.gz. • Pastikan instalasi perangkat lunak komputer anda telah memenuhi prasyarat yang dijelaskan di https://developer.mozilla.org/enUS/Add ons/SDK/Tutorials/Installation#Prerequisites. • Lalu, lakukan instalasi sesuai petunjuk di https://developer.mozilla.org/enUS/Add ons/SDK/Tutorials/Installation#Installation.
69.2
Mempersiapkan Addon
Terlebih dahulu mengatur variabel environment (Penulis menginstalasi Addon di direktori /opt/sources/firefox/addonsdk1.17) dan menginisialisasi projek addon (perhatikan perintah cfx init) di direktori /opt/course/web/myaddon: % cd /opt/course/firefox/addon-sdk-1.17 % source bin/activate Welcome to the Add-on SDK. For the docs, visit https://addons.mozilla.org/en-US/developers/docs/sdk/latest/ % mkdir /opt/course/web/myaddon % cd /opt/course/web/myaddon % cfx init * lib directory created * data directory created * test directory created * generated jID automatically: jid1-tv3FJKTvOXD3iA * package.json written * test/test-main.js written * lib/main.js written 41 Lihat https://developer.mozilla.org/en/Add-ons/SDK. Linux System Programming in C
276
Datatrans Informatika
Your sample add-on is now ready. Do "cfx test" to test it and "cfx run" to try it.
Have fun!
Anda memperoleh struktur direktori sebagai berikut: % tree . ├── data ├── lib │ └── main.js ├── package.json └── test └── test-main.js
3 directories, 3 file
File main.js di bawah direkrori lib desebut addon script. Library jsctypes hanya dapat di load di script tersebut. Addon script tidak dapat berkomunikasi langsung dengan page script (script halaman web), harus melalui content script. Kita akan membuat content script code.js di bawah direktori data. % touch data/code.js % tree . ├── data │ └── code.js ├── lib │ └── main.js ├── package.json └── test └── test-main.js
3 directories, 4 files
69.3
Kerangka
Hubungan antara page script, content script, addon script dan shared library (mylib.so) adalah sebagai berikut:
Gambar 23: Interaksi Addon untuk Membaca File Teks
Linux System Programming in C
277
Datatrans Informatika
Page script berinteraksi dengan content script menggunakan custom event. Di dalam add on, content script berinteraksi dengan addon script menggunakan port.emit dan port.on. Hanya addon script yang dapat berinterkasi dengan library jsctypes untuk mengakses shared library mylib.so.
<meta http-equiv="content-type" content="text/html; charset=utf8" /> My Add-on <script type="text/javascript"> function clicked() { var s = document.getElementById("lampu").value; var d = parseInt(s, 10); d = isNaN(d) ? 0 : d; var event = document.createEvent('CustomEvent'); event.initCustomEvent("lampu", true, true, { code: d }); document.documentElement.dispatchEvent(event); } function woClick() { var d = document.getElementById('data'); while (d.firstChild) d.removeChild(d.firstChild); var s = document.getElementById('file').value; var event = document.createEvent('CustomEvent'); event.initCustomEvent("readwo", true, true, { path: s }); document.documentElement.dispatchEvent(event); } window.addEventListener("workorder", function(event) { var data=event.detail; var span1 = document.createElement('span'); span1.innerHTML=data.wo.concat(' '); var span2 = document.createElement('span'); span2.innerHTML=data.qty; var div = document.createElement('div'); div.appendChild(span1); div.appendChild(span2); var d = document.getElementById('data'); d.appendChild(div); }, false);
Salin file index.html ke direktori aplikasi di web server. Misalnya, ke direktori aplikasi myaddon di web server tomcat (gunakan privilege root jika diperlukan): %
mkdir /var/lib/tomcat/webapps/myaddon
Linux System Programming in C
278
Datatrans Informatika
%
cp index.html /var/lib/tomcat/webapps/myaddon
69.5
Membuat Content Script
Sebagaimana telah dijelaskan, untuk membangun addon kita mempersiapkan content script code.js: Listing 188. Content Script — code.js 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
}); worker.port.on("readwo", function(filepath) { var callbackType = ctypes.FunctionType( ctypes.default_abi, ctypes.void_t, [ctypes.char.ptr, ctypes.int32_t] ).ptr; var callback_fn=callbackType(showWo); var libc = ctypes.open("mylib.so"); var func = libc.declare("readwo", ctypes.default_abi, ctypes.void_t, ctypes.char.ptr, ctypes.voidptr_t); func(filepath, callback_fn); libc.close(); }); } });
Memdebug Paket Addon
Mari mengingat kembali bahwa kita telah menginstalasi Addon SDK di /opt/sources/firefox/addonsdk1.17 dan menginisialisasi projek Addon di direktori /opt/course/web/myaddon42. Guna memeriksa jika ada kekeliruan dalam script addon, mari mendebugnya: % cd /opt/course/firefox/addon-sdk-1.17 % source bin/activate Welcome to the Add-on SDK. For the docs, visit https://addons.mozilla.org/en-US/developers/docs/sdk/latest/ % cd /opt/course/web/myaddon % cfx run
Pesan debug dan error (jika ada) ditampilkan di terminal.
69.8
Membuild Paket Addon
Jika lulus proses debug, kita dapat membuild paket Addon:
% cd /opt/course/firefox/addon-sdk-1.17 % source bin/activate Welcome to the Add-on SDK. For the docs, visit https://addons.mozilla.org/en-US/developers/docs/sdk/latest/ % cd /opt/course/web/myaddon % cfx xpi Exporting extension to myaddon.xpi.
Kita telah membuild paket instalasi myaddon.xpi. Mari memeriksa struktur direktori: % tree . ├── data │ └── code.js ├── lib │ └── main.js ├── myaddon.xpi ├── package.json └── test 42 Lihat halaman 276. Linux System Programming in C
280
Datatrans Informatika
└── test-main.js 3 directories, 5 files
69.9
Menginstalasi Addon
Pastikan web server telah distart. Launch browser firefox, minimal versi 26 (Mozilla Addon SDK terakhir mensupport minimum firefox versi 26). Addon diiinstalasi dengan mengopen file myaddon.xpi:
Gambar 24: Open File
69.10 Mengujicoba Dalam browser firefox minimun versi 26, load halaman web index.html, misalnya untuk server web tomcat di localhost: http://127.0.0.1:8080/myaddon/index.html
Gambar 25: Mengujicoba Addon Kesimpulan Menggunakan paket Addon, kita dapat mengatasi hambatan privilege dan mengimplementasikan jsctypes di browser firefox versi terbaru. Linux System Programming in C