]>
wirehaze git hosting - ppos.git/blob - ppos/hardware/disk.c
1 // PingPongOS - PingPong Operating System
2 // Prof. Carlos A. Maziero, DINF UFPR
3 // Versão 2.0 -- Junho de 2025
5 // ATENÇÃO: ESTE ARQUIVO NÃO DEVE SER ALTERADO
6 // ALTERAÇÕES SERÃO DESCARTADAS NA CORREÇÃO.
8 // Implementação do disco virtual, que simula um disco rígido.
10 // para depurar a operação do disco
11 //#define DEBUG_DISK 1
13 // padrão de API UNIX a usar (para sigaction)
14 #define _XOPEN_SOURCE 700
20 #include <sys/types.h>
30 // parâmetros de operação do disco simulado
31 #define DISK_BLOCK_SIZE 64 // tamanho de cada bloco, em bytes
32 #define DISK_DELAY_MIN 30 // atraso minimo, em milisegundos
33 #define DISK_DELAY_MAX 300 // atraso maximo, em milisegundos
34 #define DISK_SIGNAL SIGRTMIN // sinal a ser usado no timer interno
36 //----------------------------------------------------------------------
38 // estrutura com os dados internos do disco (estado inicial desconhecido)
41 int status
; // estado do disco
42 char *file
; // nome do arquivo que simula o disco
43 int fd
; // descritor do arquivo que simula o disco
44 int numblocks
; // numero de blocos do disco
45 int blocksize
; // tamanho dos blocos em bytes
46 char *buffer
; // buffer da próxima operação (read/write)
47 int prev_block
; // bloco da ultima operação
48 int next_block
; // bloco da próxima operação
49 int delay_min
, delay_max
; // tempos de acesso mínimo e máximo
50 timer_t timer
; // timer que simula o tempo de acesso
51 struct itimerspec delay
; // struct do timer de tempo de acesso
52 struct sigevent sigev
; // evento associado ao timer
53 struct sigaction signal
; // tratador de sinal do timer
57 static struct disk_t disk
= {.status
= DISK_STATUS_UNKNOWN
};
59 //----------------------------------------------------------------------
61 // arma o timer que simula o tempo de acesso ao disco;
62 // ao disparar, ele gera um sinal DISK_SIGNAL
63 static void disk_settimer()
67 // tempo no intervalo [DISK_DELAY_MIN ... DISK_DELAY_MAX], proporcional a
68 // distancia entre o proximo bloco a ler (next_block) e a ultima leitura
69 // (prev_block), somado a um pequeno fator aleatorio
70 time_ms
= abs(disk
.next_block
- disk
.prev_block
) *
71 (disk
.delay_max
- disk
.delay_min
) /
74 random() % (disk
.delay_max
- disk
.delay_min
) / 10;
77 printf("DISK: [From block %d to block %d in %d ms]\n",
78 disk
.prev_block
, disk
.next_block
, time_ms
);
81 // primeiro disparo, em nano-segundos,
82 disk
.delay
.it_value
.tv_nsec
= time_ms
* 1000000;
84 // primeiro disparo, em segundos
85 disk
.delay
.it_value
.tv_sec
= time_ms
/ 1000;
87 // próximos disparos nao ocorrem (disparo único)
88 disk
.delay
.it_interval
.tv_nsec
= 0;
89 disk
.delay
.it_interval
.tv_sec
= 0;
92 if (timer_settime(disk
.timer
, 0, &disk
.delay
, NULL
) == -1)
98 printf("DISK: timer is set\n");
102 //----------------------------------------------------------------------
104 // trata o sinal do timer que simula o tempo de acesso ao disco
105 static void disk_sighandle(int)
108 printf("DISK: signal received\n");
109 printf("fd: %d, block %d, size %d\n", disk
.fd
, disk
.next_block
,
113 // verificar qual a operação pendente e realizá-la
116 case DISK_STATUS_READ
:
117 // faz a leitura previamente agendada
118 pread(disk
.fd
, disk
.buffer
, disk
.blocksize
,
119 disk
.next_block
* disk
.blocksize
);
122 case DISK_STATUS_WRITE
:
123 // faz a escrita previamente agendada
124 pwrite(disk
.fd
, disk
.buffer
, disk
.blocksize
,
125 disk
.next_block
* disk
.blocksize
);
129 // erro: estado desconhecido
130 perror("DISK: unknown disk state");
134 // guarda numero de bloco da ultima operação
135 disk
.prev_block
= disk
.next_block
;
137 // disco se torna ocioso novamente
138 disk
.status
= DISK_STATUS_IDLE
;
140 // gera uma IRQ virtual para o "kernel" do usuário
141 raise(IRQ_DISK
+ SIGRTMIN
);
144 //----------------------------------------------------------------------
146 // inicia o disco virtual contido em "disk_image"
147 // retorno: 0 (sucesso) ou -1 (erro)
148 static int disk_init(char *disk_image
)
150 // o disco já foi iniciado ?
151 if (disk
.status
!= DISK_STATUS_UNKNOWN
)
154 // estado atual do disco
155 disk
.status
= DISK_STATUS_IDLE
;
156 disk
.next_block
= disk
.prev_block
= 0;
158 // abre o arquivo no disco (leitura/escrita, sincrono)
159 disk
.file
= disk_image
;
160 disk
.fd
= open(disk
.file
, O_RDWR
| O_SYNC
);
167 // define seu tamanho em blocos
168 disk
.blocksize
= DISK_BLOCK_SIZE
;
169 disk
.numblocks
= lseek(disk
.fd
, 0, SEEK_END
) / disk
.blocksize
;
171 // ajusta atrasos mínimo e máximo de acesso no disco
172 disk
.delay_min
= DISK_DELAY_MIN
;
173 disk
.delay_max
= DISK_DELAY_MAX
;
175 // associa sinal do timer interno ao handle apropriado
176 disk
.signal
.sa_handler
= disk_sighandle
;
177 sigemptyset(&disk
.signal
.sa_mask
);
178 disk
.signal
.sa_flags
= SA_NODEFER
;
179 sigaction(DISK_SIGNAL
, &disk
.signal
, 0);
181 // cria o timer que simula o tempo de acesso ao disco
182 disk
.sigev
.sigev_notify
= SIGEV_SIGNAL
;
183 disk
.sigev
.sigev_signo
= DISK_SIGNAL
;
184 if (timer_create(CLOCK_REALTIME
, &disk
.sigev
, &disk
.timer
) == -1)
191 printf("DISK: initialized\n");
197 //----------------------------------------------------------------------
199 // função que implementa a interface de acesso ao disco virtual
200 int hw_disk_cmd(int cmd
, int block
, void *buffer
)
203 printf("DISK: received command %d\n", cmd
);
210 return (disk_init(buffer
));
212 // solicita status do disco
213 case DISK_CMD_STATUS
:
214 return (disk
.status
);
216 // solicita tamanho do disco
217 case DISK_CMD_DISKSIZE
:
218 if (disk
.status
== DISK_STATUS_UNKNOWN
)
220 return (disk
.numblocks
);
222 // solicita tamanho de bloco
223 case DISK_CMD_BLOCKSIZE
:
224 if (disk
.status
== DISK_STATUS_UNKNOWN
)
226 return (disk
.blocksize
);
228 // solicita atraso mínimo
229 case DISK_CMD_DELAYMIN
:
230 if (disk
.status
== DISK_STATUS_UNKNOWN
)
232 return (disk
.delay_min
);
234 // solicita atraso máximo
235 case DISK_CMD_DELAYMAX
:
236 if (disk
.status
== DISK_STATUS_UNKNOWN
)
238 return (disk
.delay_max
);
240 // solicita operação de leitura ou de escrita
243 if (disk
.status
!= DISK_STATUS_IDLE
)
247 if (block
< 0 || block
>= disk
.numblocks
)
250 // registra que ha uma operação pendente
251 disk
.buffer
= buffer
;
252 disk
.next_block
= block
;
253 if (cmd
== DISK_CMD_READ
)
254 disk
.status
= DISK_STATUS_READ
;
256 disk
.status
= DISK_STATUS_WRITE
;
258 // arma o timer que simula o atraso do disco
268 //----------------------------------------------------------------------