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
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
|
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE manualpage SYSTEM "./style/manualpage.dtd">
<?xml-stylesheet type="text/xsl" href="./style/manual.es.xsl"?>
<!-- English Revision: 421174:587442 (outdated) -->
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<manualpage metafile="dso.xml.meta">
<title>Soporte de Objetos Dinamicos Compartidos (DSO)</title>
<summary>
<p>El servidor HTTP Apache es un programa modular en el que el
administrador puede elegir qué funcionalidades se incluyen
mediante la selección de un conjunto de módulos. En
primer lugar, los módulos pueden compilarse de manera
estática en el binario <program>httpd</program>. De forma
alternativa, los módulos también pueden compilarse como
Objetos Dinamicos Compartidos (DSOs) que existen de forma
independiente del archivo binario <program>httpd</program>. Los
módulos que se deseen usar como objetos dinámicos
compartidos pueden compilarse al mismo tiempo que el servidor, o
pueden compilarse en otro momento y ser añadidos después
usando la Herramienta de Extensión de Apache
(<program>apxs</program>).</p>
<p>Este documento describe cómo usar los módulos en
forma de objeto dinámico compartido (DSO) así como los
fundamentos teóricos que hay detrás para explicar su
funcionamiento.</p>
</summary>
<section id="implementation"><title>Implementación</title>
<related>
<modulelist>
<module>mod_so</module>
</modulelist>
<directivelist>
<directive module="mod_so">LoadModule</directive>
</directivelist>
</related>
<p>Cargar módulos de Apache individualmente como objetos
dinámicos compartidos (DSO) es posible gracias a un
módulo llamado <module>mod_so</module> que debe compilarse
estáticamente en el núcleo (kernel) de Apache. Es el
único módulo junto con el módulo
<module>core</module> que no se puede usar como objeto
dinámico compartido. Prácticamente todos los demás
módulos distribuidos con Apache se pueden usar como objetos
dinámicos compartidos individualmente siempre y cuando se
haya activado la posibilidad de usarlos con la opción de
<program>configure</program>
<code>--enable-<em>module</em>=shared</code> tal y como se
explicó en la <a href="install.html">documentación de
instalación</a>. Una vez que haya compilado un módulo
como objeto dinámico compartido y le haya puesto un nombre
del tipo <code>mod_foo.so</code>, puede cargarlo al iniciar o
reiniciar el servidor usando el comando <directive
module="mod_so">LoadModule</directive> de <module>mod_so</module>
en el fichero <code>httpd.conf</code>.</p>
<p>Para simplificar la creación de objetos dinámicos
compartidos para Apache (especialmente módulos de terceras
partes) está disponible un nuevo programa de soporte llamado
<program>apxs</program> (<em>APache eXtenSion</em>). Puede usar
este programa para crear módulos como objetos dinámicos
compartidos <em>sin tener que</em> crearlos al mismo tiempo que
compila su servidor Apache. La idea es simple: cuando se instala
Apache el procedimiento <code>make install</code> de
<program>configure</program> @@@ installs the Apache C header
files and puts the platform-dependent compiler and linker flags
for building DSO files into the apxs program / instala los
ficheros de cabecera de C de Apache y especifica las opciones de
compilación y enlace dependientes de la plataforma para
generar objetos dinámicos compartidos con
<program>apxs</program>. De esta manera el usuario puede usar
<program>apxs</program> para compilar el código fuente de
módulos de Apache de manera independiente y sin tener que
preocuparse por las opciones de compilación y enlace
dependientes de la plataforma que soportan objetos dinámicos
compartidos.</p>
</section>
<section id="usage"><title>Resumen de uso</title>
<p>Para que se haga una idea de lo que permite el soporte de
objetos dinámicos compartidos en Apache 2.0, aquí tiene
un resumen breve pero conciso:</p>
<ol>
<li>
Construir e instalar un módulo <em>incluido en la
distribución</em> de Apache, digamos
<code>mod_foo.c</code>, como un objeto dinámico
compartido de nombre <code>mod_foo.so</code>:
<example>
$ ./configure --prefix=/path/to/install --enable-foo=shared<br />
$ make install
</example>
</li>
<li>
Construir e instalar un módulo de Apache de una
<em>tercera parte</em>, digamos <code>mod_foo.c</code>, como
un objeto dinámico compartido de nombre
<code>mod_foo.so</code>:
<example>
$ ./configure --add-module=module_type:/path/to/3rdparty/mod_foo.c --enable-foo=shared<br />
$ make install
</example>
</li>
<li>
Configurar Apache para poder <em>instalar después</em>
objetos dinámicos compartidos:
<example>
$ ./configure --enable-so<br />
$ make install
</example>
</li>
<li>
Construir e instalar un módulo de Apache de una
<em>tercera parte</em>, digamos <code>mod_foo.c</code>, como
un objeto dinámico compartido de nombre
<code>mod_foo.so</code> <em>fuera</em> de la estructura de
directorios de Apache usando <program>apxs</program>:
<example>
$ cd /path/to/3rdparty<br />
$ apxs -c mod_foo.c<br />
$ apxs -i -a -n foo mod_foo.la
</example>
</li>
</ol>
<p>En todos los casos, una vez que se compila el objeto
dinámico compartido, debe usar una directiva <directive
module="mod_so">LoadModule</directive> en
<code>httpd.conf</code> para activar dicho módulo.</p>
</section>
<section id="background"><title>Fundamentos teoróricos
detrás de los objetos dinámicos compartidos</title>
<p>En las versiones modernas de Unix, existe un mecanismo
especialmente útil normalmente llamado enlazado/carga de
<em>Objetos Dinámicos Compartidos</em> (DSO). Este mecanismo
ofrece una forma de construir trozos de código de programa en
un formato especial para cargarlo en tiempo de ejecución en
el espacio de direcciones de memoria de un programa
ejecutable.</p>
<p>Esta carga puede hacerse de dos maneras: automáticamente
con un programa de sistema llamado <code>ld.so</code> al inicio de
un programa ejecutable o manualmente desde dentro del programa en
ejecución con una interfaz programática del sistema al
cargador de Unix mediante llamadas al sistema
<code>dlopen()/dlsym()</code>.</p>
<p>Si se usa el primer método, los objetos dinámicos
compartidos se llaman normalmente <em>librerías
compartidas</em> ó <em>librerías DSO</em> y se
nombran como <code>libfoo.so</code> o
<code>libfoo.so.1.2</code>. Residen en un directorio de
sistema (normalmente <code>/usr/lib</code>) y el enlace con el
programa ejecutable se establece al construir la librería
especificando la opción<code>-lfoo</code> al comando de
enlace. Esto incluye las referencias literales a las
librerías en el programa ejecutable de manera que cuando
se inicie, el cargador de Unix será capaz de localizar
<code>libfoo.so</code> en <code>/usr/lib</code>, en rutas
referenciadas literalmente mediante opciones del linker como
<code>-R</code> o en rutas configuradas mediante la variable
de entorno <code>LD_LIBRARY_PATH</code>. Entonces se resuelven
los símbolos (todavía no resueltos) en el programa
ejecutable que están presentes en el objeto dinámico
compartido.</p>
<p>Los símbolos en el programa ejecutable no están
referenciados normalmente en el objeto dinámico compartido
(porque son librerías reusables de propósito general) y
por tanto, no se producen más resoluciones. El programa
ejecutable no tiene que hacer nada por sí mismo para usar los
símbolos del objeto dinámico compartido porque todo el
trabajo de resolución lo hace @@@ Unix loader / el cargador
de Unix @@@. (De hecho, el código para invocar
<code>ld.so</code> es parte del código que se ejecuta al
iniciar, y que hay en cualquier programa ejecutable que haya sido
construido de forma no estática). La ventaja de cargar
dinámicamente el código de las librerías comunes es
obvia: el código de las librerías necesita ser almacenado
solamente una vez, en una librería de sistema como
<code>libc.so</code>, ahorrando así espacio en disco.</p>
<p>Por otro lado, los objetos dinámicos compartidos
también suelen llamarse <em>objetos compatidos</em> o
<em>ficheros DSO</em> y se les puede nombrar con cualquier
extensión (aunque su nombre canónico es
<code>foo.so</code>). Estos archivos normalmente permanecen
dentro de un directorio específico del programa y no se
establecen enlaces automáticamente con los programas
ejecutables con los que se usan. En lugar de esto, el
programa ejecutable carga manualmente el objeto dinámico
compartido en tiempo de ejecución en su espacio de
direcciones de memoria con <code>dlopen()</code>. En ese
momento no se resuelven los símbolos del objeto
dinámico compartido para el programa ejecutable. En lugar
de esto, el cargador de Unix resuelve automáticamente los
símbolos (aún no resueltos en el objeto
dinámico compartido del conjunto de símbolos
exportados por el programa ejecutable y de las librerías
DSO que tenga ya cargadas (especialmente todos los
símbolos de la omnipresente <code>libc.so</code>). De
esta manera el objeto dinámico compartido puede conocer
el conjunto de símbolos del programa ejecutable como si
hubiera sido enlazado estáticamente en un primer
momento.</p>
<p>Finalmente, para beneficiarse de la API de las DSOs, el
programa ejecutable tiene que resolver los símbolos
particulares de la DSO con <code>dlsym()</code> para ser usado
más tarde dentro de tablas de direccionamiento (dispatch
tables) <em>etc.</em> En otras palabras: El programa ejecutable
tiene que resolver manualmente cada uno de los símbolos que
necesita para poder usarlo después. La ventaja de ese
mecanismo es que las partes opcionales del programa no necesitan
ser cargadas (y por tanto no consumen memoria) hasta que se
necesitan por el programa en cuestión. Cuando es necesario,
estas partes del programa pueden cargarse dinámicamente para
expandir las funcionalidades básicas del programa.</p>
<p>Aunque este mecanismo DSO parece muy claro, hay al menos un
paso de cierta dificultad: la resolución de los símbolos
que usa el programa ejecutable por la DSO cuando se usa una DSO
para extender la funcionalidad de una programa (segundo caso). Por
qué? Porque la resolución inversa de símbolos de
DSOs del conjunto de símbolos del programa ejecutable se hace
en contra del diseño de la librería (donde la
librería no tiene conocimiento sobre los programas que la
usan) y tampoco está disponible en todas las plataformas no
estandarizadas. En la práctica los símbolos globales del
programa ejecutable están disponibles para su uso en una
DSO. El mayor problema que hay que resolver cuando se usan DSOs
para extender un programa en tiempo de ejecución es encontrar
un modo de forzar al enlazador a exportar todos los símbolos
globales.</p>
<p>El enfoque de las librerías compartidas es bastante
típico, porque es para lo que se diseño el mecanismo
DSO, por tanto se usa para casi todos los tipos de librerías
que incluye el sistema operativo. Por otro lado, no muchos
programas usan objetos compartidos para expandir sus
funcionalidades.</p>
<p>En 1998, había solamente unos pocos programas disponibles
que usaban el mecanismo DSO para extender su funcionalidad en
tiempo de ejecucion: Perl 5 (por medio de su mecanismo XS y el
módulo DynaLoader), Netscape Server, <em>etc.</em> A partir
de la version 1.3, Apache se unió a este grupo, Apache usa
desde entonces una concepción modular para extender su
funcionalidad e internamente usa un enfoque de tablas de
direccionamiento (dispatch-list-based) para enlazar módulos
externos con las funcionalidades propias del servidor. De esta
manera, Apache puede usar el mecanismo DSO para cargar sus
módulos en tiempo de ejecución.</p>
</section>
<section id="advantages"><title>Ventajas e Inconvenientes</title>
<p>Las características de las librerías dinámicas
compartidas arriba explicadas tienen las siguientes ventajas:</p>
<ul>
<li>El servidor es mucho más flexible en tiempo de
ejecución porque pueden añadirse módulos mediante
comandos de configuración <directive
module="mod_so">LoadModule</directive> en
<code>httpd.conf</code> en lugar de tener que hacerlo con las
opciones de <program>configure</program> al compilar. Por
ejemplo, de esta manera uno puede ejecutar diferentes instancias
del servidor (estándar & SSL, mínima & super
potente [mod_perl, PHP3], <em>etc.</em>) con una única
instalación de Apache.</li>
<li>El servidor puede ser extendido fácilmente con
módulos de terceras partes después de la
instalación. Esto es un gran beneficio al menos para los
mantenedores de paquetes de distribuciones, que pueden crear un
paquete básico de Apache y paquetes adicionales que
contengan extensiones tales como PHP3, mod_perl, mod_fastcgi,
<em>etc.</em></li>
<li>Facilita la labor de hacer prototipos de módulos de
Apache porque con el dúo DSO/<program>apxs</program> se
puede trabajar fuera de la estructura de directorios de Apache y
únicamente es necesario el comando <code>apxs -i</code>
seguido del comando <code>apachectl restart</code> para probar
la nueva versión del módulo que se está
desarrollando.</li>
</ul>
<p>DSO presenta los siguientes inconvenientes:</p>
<ul>
<li>El mecanismo DSO no puede ser usado en todas las plataformas
porque no todos los sistemas operativos soportan la carga
dinámica de código en el espacio de direcciones de
memoria de un programa.</li>
<li>El servidor es aproximadamente un 20% más lento
iniciándose por la sobrecarga que implica la
resolución de símbolos por parte del cargador de Unix.</li>
<li>El servidor es aproximadamente un 5% más lento
ejecutándose en algunas plataformas porque el código
posicionado independientemente (PIC) necesita algunas veces
procesos bastante complicados para calcular direcciones
relativas que no son en principio tan rápidos como los que
se usan para calcular direcciones absolutas.</li>
<li>Como los módulos DSO no pueden enlazarse a otras
librerías basadas en DSO (<code>ld -lfoo</code>) en todas
las plataformas (por ejemplo en las plataformas basadas en a.out
normalmente no puede ser usada esta funcionalidad, mientras que
sí puede ser usada en las plataformas basadas en ELF) no se
puede usar el mecanismo DSO para todos los tipos de
módulos. En otras palabras, los módulos compilados
como ficheros DSO solamente pueden usar símbolos del
núcleo (kernel) de Apache, los de las librerías de C
(<code>libc</code>) y de todas las demas librerías
dinámicas o estáticas usadas por el núcleo de
Apache, o de archivos de librerías estáticas
(<code>libfoo.a</code>) que contengan código independiente
de su posición. Las únicas posibilidades para usar
otro código es asegurarse de que el núcleo de Apache
contiene una referencia a él o cargar el código por
medio de <code>dlopen()</code>.</li>
</ul>
</section>
</manualpage>
|