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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
|
Let me say this in french. Sorry for english-only-speaking people, i'll translate someday.
L'idée principale motivant le développement de T/CE est celle d'un nouveau protocole entre le
noyau et les applications utilisateur.
Les objets du systèmes sont accessibles sous la forme d'un système de fichiers dans lequel on
navigue, sauf que les objets sont en fait bien plus que de simples fichiers.
Ce protocole se base sur trois définitions fondamentales :
-- Interfaces :
Une interface est un ensemble de définitions (de prototypes, donc) de méthodes qui
peuvent être implémentées par un objet du système.
Parmi les méthodes, il y a des méthodes publiques, faites pour être appellées par les
applications utilisateurs, et des méthodes internes au noyau.
-- Classe :
Une classe, c'est un regroupement d'interfaces avec leur implémentation spécifique.
-- Objet :
Un objet du système est d'une classe précise, et correspond donc à un des objets gérés
par le code de cette classe. On peut appeller toutes les méthodes des interfaces implémentées
par la classe de l'objet sur cet objet.
Ce n'est peut-être pas très clair, alors illustrons :
Interface : Keyboard
- OutputToConsole(Console)
Interface : Console
- SetActiveVT (VirtualTerminal)
- NewBufferedVT (char*) // crée un nouveau terminal virtuel - char* = le nom
- (internal) receiveKeyboardInput(int)
- (internal) repaint(char*)
- (internal) write(int, char*)
Interface : VirtualTerminal
- Read(int, char*)
- Write(int, char*)
- (internal) receiveKeyboardInput(int)
- (internal) outputToConsole(Console, int, int) // int, int = dimensions de la console
Classe : PS2Keyboard
- Garde en mémoire la console à qui il envoie les données
- Quand une touche est pressée/relâchée, appeller receiveKeyboardInput sur cette console
- Implémenter la méthode OutputToConsole pour changer la console à qui les données sont envoyées
Classe : TextConsole
- Implémente la gestion de l'écran texte VGA de base
- Garde en mémoire le VirtualTerminal actif
- Transmet l'entrée clavier au VirtualTerminal actif
- Lorsqu'on lui demande de changer le VT actif :
il signale à l'ancien VT de ne plus émettre,
il signale au nouveau VT d'émettre vers cette console
et spécifie au nouveau VT la bonne dimension d'écran
Classe : BufferedVirtualTerminal
- Il garde en mémoire LA Console vers laquelle il doit émettre, ainsi que ses dimensions
- Garde un buffer de tout ce qui passe sur la console, et un buffer de l'écran actif.
- Lorsqu'il reçoit une entrée clavier, la bufferise, puis la restitue lors du prochain appel à Read
- Lorsqu'on écrit quelque chose dessus avec Write, il le garde dans son buffer
et le donne aussi au terminal virtuel de sortie, s'il y en a un
Implémentation :
// Structures
struct Interface {
char* name;
int method_count;
int public_method_count;
NumberedMethod numberedMethods[];
int methodNumbers[];
};
struct NumberedMethod {
Interface *iface;
int numberInIface;
};
type MethodPtr (function pointer type);
struct InterfaceImpl {
Interface *interface;
MethodPtr methods[];
};
struct Class {
char* name;
MethodPtr *findChild;
InterfaceImpl interfaces[]; //zero-terminated list
};
struct Object {
Class *class;
void *data;
};
// setup code
void Class_setup(Class* class) {
for (int i = 0; class->interfaces[i] != 0; i++) {
Interface_setup(class->interfaces[i]->interface)
}
}
ExpandableTable<NumberedMethod*> allMethods;
void Interface_setup(Interface* iface) {
if (iface->numberedMethods != 0) return;
iface->numberedMethods = malloc(iface->method_count * sizeof(NumberedMethod));
iface->methodNumbers = malloc(iface->method_count * sizeof(int));
for (int i = 0; i < iface->method_count; i++) {
iface->methodNumbers[i] = allMethods.register(&impl->numberedMethods[i])
iface->numberedMethods[i]->numberInIface = i;
iface->numberedMethods[i]->ptr = impl->methods[i];
}
}
void Object_callByNumber(Object *obj, int number, params...) {
NumberedMethod *method = allMethods.get(number);
for (int i = 0; obj->class->interfaces[i] != 0; i++) {
InterfaceImpl impl = obj->class->interfaces[i];
if (method->iface == impl->interface) {
MethodPtr fct = impl->methods[method->numberInIface];
return fct (params...)
}
}
return E_NOT_IMPLEMENTED;
}
// Exemple
struct ConsoleMethods {
MethodPtr SetActiveVT;
MethodPtr NewBufferedVT;
MethodPtr receiveKeyboardInput;
MethodPtr repaint;
MethodPtr write;
};
Interface ConsoleIface = {
name: "Console",
method_count: 5,
public_method_count: 2,
numberedMethods: 0, methodNumbers: 0, // internal
};
ConsoleMethods TextConsole_as_Console = {
SetActiveVT: TextConsole_SetActiveVT,
NewBufferedVT: TextConsole_NewBufferedVT,
receiveKeyboardInput: TextConsole_receiveKeyboardInput,
repaint: TextConsole_repaint,
write: TextConsole_write,
};
Class TextConsoleClass = {
name: "TextConsole",
findChild: Console_findChild,
interfaces: {
{ ConsoleIface, (MethodPtr*)TextConsole_as_Console },
0
},
};
struct TextConsole {
Object object;
//... data ...
};
// Other example
struct FolderMethods {
MethodPtr GetChildList;
};
Interface FolderIface = {
name: "Folder",
method_count: 1,
public_method_count: 1,
numberedMethods: 0, methodNumbers: 0, // internal
};
|