ftp://ftp.redhat.com/pub/redhat/linux/rawhide/SRPMS/SRPMS/gnome-vfs2-2.3.8-1.src.rpm
[gnome-vfs-httpcaptive.git] / doc / html / writing-modules.html
1 <HTML
2 ><HEAD
3 ><TITLE
4 >Writing Modules</TITLE
5 ><META
6 NAME="GENERATOR"
7 CONTENT="Modular DocBook HTML Stylesheet Version 1.76b+
8 "><LINK
9 REL="HOME"
10 TITLE="GnomeVFS - Filesystem Abstraction library"
11 HREF="index.html"><LINK
12 REL="UP"
13 TITLE="Filesystem Modules"
14 HREF="modules.html"><LINK
15 REL="PREVIOUS"
16 TITLE="Filesystem Modules"
17 HREF="modules.html"><LINK
18 REL="NEXT"
19 TITLE="MIME typing"
20 HREF="gnome-vfs-gnome-vfs-mime.html"><META
21 NAME="GENERATOR"
22 CONTENT="GTK-Doc V0.10 (SGML mode)"><STYLE
23 TYPE="text/css"
24 >.synopsis, .classsynopsis {
25     background: #eeeeee;
26     border: solid 1px #aaaaaa;
27     padding: 0.5em;
28 }
29 .programlisting {
30     background: #eeeeff;
31     border: solid 1px #aaaaff;
32     padding: 0.5em;
33 }
34 .variablelist {
35     padding: 4px;
36     margin-left: 3em;
37 }
38 .navigation {
39     background: #ffeeee;
40     border: solid 1px #ffaaaa;
41     margin-top: 0.5em;
42     margin-bottom: 0.5em;
43 }
44 .navigation a {
45     color: #770000;
46 }
47 .navigation a:visited {
48     color: #550000;
49 }
50 .navigation .title {
51     font-size: 200%;
52 }</STYLE
53 ></HEAD
54 ><BODY
55 CLASS="REFENTRY"
56 BGCOLOR="#FFFFFF"
57 TEXT="#000000"
58 LINK="#0000FF"
59 VLINK="#840084"
60 ALINK="#0000FF"
61 ><TABLE
62 WIDTH="100%"
63 CLASS="navigation"
64 SUMMARY="Navigation header"
65 CELLPADDING="2"
66 CELLSPACING="2"
67 ><TR
68 VALIGN="middle"
69 ><TD
70 ><A
71 ACCESSKEY="p"
72 HREF="modules.html"
73 ><IMG
74 SRC="left.png"
75 WIDTH="24"
76 HEIGHT="24"
77 BORDER="0"
78 ALT="Prev"></A
79 ></TD
80 ><TD
81 ><A
82 ACCESSKEY="u"
83 HREF="modules.html"
84 ><IMG
85 SRC="up.png"
86 WIDTH="24"
87 HEIGHT="24"
88 BORDER="0"
89 ALT="Up"></A
90 ></TD
91 ><TD
92 ><A
93 ACCESSKEY="h"
94 HREF="index.html"
95 ><IMG
96 SRC="home.png"
97 WIDTH="24"
98 HEIGHT="24"
99 BORDER="0"
100 ALT="Home"></A
101 ></TD
102 ><TH
103 WIDTH="100%"
104 align="center"
105 >GnomeVFS - Filesystem Abstraction library</TH
106 ><TD
107 ><A
108 ACCESSKEY="n"
109 HREF="gnome-vfs-gnome-vfs-mime.html"
110 ><IMG
111 SRC="right.png"
112 WIDTH="24"
113 HEIGHT="24"
114 BORDER="0"
115 ALT="Next"></A
116 ></TD
117 ></TR
118 ></TABLE
119 ><H1
120 ><A
121 NAME="WRITING-MODULES"
122 ></A
123 >Writing Modules</H1
124 ><DIV
125 CLASS="REFNAMEDIV"
126 ><A
127 NAME="AEN7588"
128 ></A
129 ><H2
130 >Name</H2
131 >Writing Modules&nbsp;--&nbsp;basic gnome-vfs module concepts</DIV
132 ><DIV
133 CLASS="REFSECT1"
134 ><A
135 NAME="INTRODUCTION"
136 ></A
137 ><H2
138 >Introduction</H2
139 ><P
140 >This section will introduce the basic concepts that are
141       needed for writing GNOME Virtual File System modules.</P
142 ><DIV
143 CLASS="REFSECT2"
144 ><A
145 NAME="URIS"
146 ></A
147 ><H3
148 >GNOME VFS URIs (Uniform Resource Identifiers)</H3
149 ><P
150 >The GNOME Virtual file system uses URIs similiar to the
151         standard WWW URIs.  The basic difference between a VFS URI and
152         WWW URI is that, while with WWW URIs you can only use a single
153         protocol for accessing a certain file, with GNOME VFS URIs you
154         can combine different access methods in sequence.</P
155 ><P
156 >For example, suppose you want to access file
157         <TT
158 CLASS="FILENAME"
159 >hello.c</TT
160 > in a <TT
161 CLASS="FILENAME"
162 >tar.gz</TT
163 >
164         file which is in turn accessible through FTP from a remote
165         machine.  In order to access this file, you would need to:</P
166 ><P
167 ></P
168 ><OL
169 TYPE="1"
170 ><LI
171 ><P
172 >Connect to the FTP site.</P
173 ></LI
174 ><LI
175 ><P
176 >Fetch the <TT
177 CLASS="FILENAME"
178 >tar.gz</TT
179 >
180         file.</P
181 ></LI
182 ><LI
183 ><P
184 >Decompress the <TT
185 CLASS="FILENAME"
186 >tar.gz</TT
187 > file using
188           GZIP.</P
189 ></LI
190 ><LI
191 ><P
192 >Extract <TT
193 CLASS="FILENAME"
194 >hello.c</TT
195 > from the resulting
196           uncompressed <TT
197 CLASS="FILENAME"
198 >tar</TT
199 > file.</P
200 ></LI
201 ></OL
202 ><P
203 >The GNOME Virtual File System lets you express this by
204         combining the three access methods (i.e. tar, GZIP and FTP)
205         into a single URI.  Access methods are combined in the URI by
206         using the `#' character, followed by the name for the access
207         method and the subpath for that specific access method.  The
208         subpath can be omitted for those storage methods that do not
209         need a path to retrieve the file.  (For example, a GZIP file
210         always contains a single uncompressed file, so no path is
211         needed to locate the uncompressed file within the GZIP file.
212         But on the other hand, the TAR method requires a path to
213         locate a specific file or directory.)</P
214 ><P
215 >For example, in the case we outlined above, the URI would
216         look something like:</P
217 ><PRE
218 CLASS="PROGRAMLISTING"
219 >&#13;        ftp://username:password@host.net/path/to/file.tar.gz#gzip#tar/path/to/hello.c</PRE
220 ><P
221 >Each method/subpath couple is called a <I
222 CLASS="FIRSTTERM"
223 >URI
224       element</I
225 >.  When URI elements are combined like this,
226       each URI element uses the previous one to access a base resource
227       into which it will look up a file, using the subpath
228       information.  For this reason, we will say that each element is
229       the <I
230 CLASS="FIRSTTERM"
231 >parent</I
232 > element for the following one.</P
233 ><P
234 >The first URI element, the one which has no parent, is
235       called the <I
236 CLASS="FIRSTTERM"
237 >toplevel element</I
238 >.  It does not
239       use the `#' character; instead, it uses the standard syntax of
240       WWW URIs: </P
241 ><PRE
242 CLASS="PROGRAMLISTING"
243 >&#13;        method://user:password@host/path/to/file</PRE
244 ><P
245 >This way, normal WWW URIs can be used with the GNOME Virtual
246       File System.</P
247 ><P
248 >Toplevel elements are also special because they let users
249         specify user names, passwords and host names, while
250         non-toplevel elements don't.</P
251 ></DIV
252 ><HR><DIV
253 CLASS="REFSECT2"
254 ><A
255 NAME="AEN7624"
256 ></A
257 ><H3
258 >The <SPAN
259 CLASS="STRUCTNAME"
260 >GnomeVFSURI</SPAN
261 > type</H3
262 ><P
263 >Within the GNOME Virtual File System library, URI elements
264       are represented by a special type,
265       <SPAN
266 CLASS="STRUCTNAME"
267 >GnomeVFSURI</SPAN
268 >, which is meant to represent
269       user-provided URIs in a machine-optimized way.  </P
270 ><P
271 >Every <SPAN
272 CLASS="STRUCTNAME"
273 >GnomeVFSURI</SPAN
274 > contains the
275       following information:</P
276 ><P
277 ></P
278 ><UL
279 ><LI
280 ><P
281 >A reference counter</P
282 ></LI
283 ><LI
284 ><P
285 >A pointer to the parent
286         <SPAN
287 CLASS="STRUCTNAME"
288 >GnomeVFSURI</SPAN
289 > URI element.</P
290 ></LI
291 ><LI
292 ><P
293 >The subpath.</P
294 ></LI
295 ><LI
296 ><P
297 >The name of the access method.</P
298 ></LI
299 ><LI
300 ><P
301 >A pointer to a
302         <SPAN
303 CLASS="STRUCTNAME"
304 >GnomeVFSMethod</SPAN
305 > object, describing the
306         access method (see below).</P
307 ></LI
308 ></UL
309 ></DIV
310 ></DIV
311 ><DIV
312 CLASS="REFSECT1"
313 ><A
314 NAME="AEN7644"
315 ></A
316 ><H2
317 >GNOME Virtual File System access method implementation</H2
318 ><P
319 >In the GNOME Virtual File System, the implementations for
320     all the access methods are loaded at runtime, as shared library
321     modules.  The modules are loaded during parsing of the string URI:
322     if the parser encounters an access method for which no
323     implementation is currently loaded, it retrieves the corresponding
324     library file, dynamically links it into the executable, and
325     initializes it.</P
326 ><P
327 >After initialization, the module returns a special
328     <SPAN
329 CLASS="STRUCTNAME"
330 >GnomeVFSMethod</SPAN
331 > object that contains
332     pointers to the various implementation functions for that specific
333     method.  By storing a pointer to this object into the
334     <SPAN
335 CLASS="STRUCTNAME"
336 >GnomeVFSURI</SPAN
337 > type, the VFS library is then
338     able to use these functions for file access.</P
339 ><DIV
340 CLASS="REFSECT2"
341 ><A
342 NAME="AEN7650"
343 ></A
344 ><H3
345 >How file access is performed</H3
346 ><P
347 >When the VFS library needs to perform some file operation,
348       it performs the following steps:</P
349 ><P
350 ></P
351 ><UL
352 ><LI
353 ><P
354 >If the URI is given in textual form (i.e. as a
355         string), it parses it and activates the necessary access method
356         modules.</P
357 ></LI
358 ><LI
359 ><P
360 >It retrieves a pointer to the lowmost
361         level URI element.</P
362 ></LI
363 ><LI
364 ><P
365 >It retrieves a pointer to the
366         <SPAN
367 CLASS="STRUCTNAME"
368 >GnomeVFSMethod</SPAN
369 > object that corresponds
370         to the access method for that URI element.</P
371 ></LI
372 ><LI
373 ><P
374 >It retrieves a pointer to the implementation
375         function for that operation from the
376         <SPAN
377 CLASS="STRUCTNAME"
378 >GnomeVFSMethod</SPAN
379 >object.</P
380 ></LI
381 ><LI
382 ><P
383 >It invokes that implementation function
384         passing the pointer to the lowmost level URI
385         element.</P
386 ></LI
387 ></UL
388 ><P
389 >Combining the access methods is always done within the
390       method implementation.  If the method implementation needs to do
391       some file operation on the the parent URI element, it can do so
392       by simply invoking the corresponding VFS function in, by using
393       the parent pointer in the <SPAN
394 CLASS="STRUCTNAME"
395 >GnomeVFSURI</SPAN
396 >
397       object. </P
398 ><P
399 >For example, suppose you have to read a simple URI like
400       the following:</P
401 ><PRE
402 CLASS="PROGRAMLISTING"
403 >&#13;        file:/home/ettore/file.gz#gzip</PRE
404 ><P
405 >In this case, the GZIP method will be invoked with a
406       pointer to the <SPAN
407 CLASS="STRUCTNAME"
408 >GnomeVFSURI</SPAN
409 > describing the
410       `gzip' part; then the GZIP method will be able to read
411       <TT
412 CLASS="FILENAME"
413 >file.gz</TT
414 > by just invoking the corresponding
415       GNOME VFS library function on its parent, and decompress it on
416       the fly. </P
417 ></DIV
418 ></DIV
419 ><DIV
420 CLASS="REFSECT1"
421 ><A
422 NAME="AEN7673"
423 ></A
424 ><H2
425 >Implementing an access method in practice</H2
426 ><P
427 >Implementing a new access method is really not difficult at
428     all.  This section explains how this is done.</P
429 ><DIV
430 CLASS="REFSECT2"
431 ><A
432 NAME="AEN7676"
433 ></A
434 ><H3
435 >Using shared libraries</H3
436 ><P
437 >Every module must be compiled as a shared library (i.e. a
438       <TT
439 CLASS="FILENAME"
440 >.so</TT
441 > file).</P
442 ><P
443 >The current way for accessing the right module for the
444       right method is very simple, and is based on file names.  In
445       practice, a module implementing access method named
446       <TT
447 CLASS="FILENAME"
448 >foo</TT
449 > must be named
450       <TT
451 CLASS="FILENAME"
452 >libfoo.so</TT
453 >.  For example, the module
454       implementing the <TT
455 CLASS="FILENAME"
456 >ftp:</TT
457 > access method is
458       called <TT
459 CLASS="FILENAME"
460 >libftp.so</TT
461 >, the module implementing
462       <TT
463 CLASS="FILENAME"
464 >#gzip</TT
465 > access is called
466       <TT
467 CLASS="FILENAME"
468 >libgzip.so</TT
469 > and so on.</P
470 ><P
471 >This might change in the future.</P
472 ></DIV
473 ><HR><DIV
474 CLASS="REFSECT2"
475 ><A
476 NAME="AEN7688"
477 ></A
478 ><H3
479 >The initialization/shutdown functions</H3
480 ><P
481 >Every shared library module must provide two functions:</P
482 ><PRE
483 CLASS="PROGRAMLISTING"
484 >&#13;GnomeVFSMethod *vfs_module_init (void);
485 void vfs_module_shutdown (GnomeVFSMethod *method);</PRE
486 ><P
487 >These are the only functions that the VFS library will
488       access directly.  All the other symbols (i.e. functions and
489       variables) in the module should be made static. </P
490 ><P
491 ><TT
492 CLASS="FUNCTION"
493 >vfs_module_init()</TT
494 > is called
495       as soon as the module is loaded in memory.  It will have to
496       return a pointer to a <SPAN
497 CLASS="STRUCTNAME"
498 >GnomeVFSMethod</SPAN
499 >
500       object that will contain the pointers to the method's
501       implementation functions.  We will describe this later. </P
502 ><P
503 ><TT
504 CLASS="FUNCTION"
505 >vfs_module_shutdown</TT
506 >, instead,
507       is called before the module is unloaded or the program that uses
508       it dies.  This functions should:</P
509 ><P
510 ></P
511 ><UL
512 ><LI
513 ><P
514 >Deallocate all the memory allocated by the
515         module.</P
516 ></LI
517 ><LI
518 ><P
519 >Close all the file descriptors associated with
520         the module.</P
521 ></LI
522 ><LI
523 ><P
524 >Kill any external process spawned by the
525         module.</P
526 ></LI
527 ><LI
528 ><P
529 >In general, make sure that any operation that
530         was going on before this function was called will be
531         interrupted correctly, as soon as possible and without any
532         leaks.</P
533 ></LI
534 ></UL
535 ></DIV
536 ><HR><DIV
537 CLASS="REFSECT2"
538 ><A
539 NAME="AEN7707"
540 ></A
541 ><H3
542 >The <SPAN
543 CLASS="STRUCTNAME"
544 >GnomeVFSMethod</SPAN
545 > object</H3
546 ><P
547 >This object is contains pointers to the module
548       implementation functions.</P
549 ><PRE
550 CLASS="PROGRAMLISTING"
551 >&#13;GnomeVFSResult (* open)              (GnomeVFSMethodHandle **method_handle_return,
552                                       GnomeVFSURI *uri,
553                                       GnomeVFSOpenMode mode
554                                       GnomeVFSCancellation *cancellation);
555
556 GnomeVFSResult (* create)            (GnomeVFSMethodHandle **method_handle_return,
557                                       GnomeVFSURI *uri,
558                                       GnomeVFSOpenMode mode,
559                                       gboolean exclusive,
560                                       guint perm
561                                       GnomeVFSCancellation *cancellation);
562
563 GnomeVFSResult (* close)             (GnomeVFSMethodHandle *method_handle
564                                       GnomeVFSCancellation *cancellation);
565
566 GnomeVFSResult (* read)              (GnomeVFSMethodHandle *method_handle,
567                                       gpointer buffer,
568                                       GnomeVFSFileSize num_bytes,
569                                       GnomeVFSFileSize *bytes_read_return
570                                       GnomeVFSCancellation *cancellation);
571
572 GnomeVFSResult (* write)             (GnomeVFSMethodHandle *method_handle,
573                                       gconstpointer buffer,
574                                       GnomeVFSFileSize num_bytes,
575                                       GnomeVFSFileSize *bytes_written_return
576                                       GnomeVFSCancellation *cancellation);
577
578 GnomeVFSResult (* seek)              (GnomeVFSMethodHandle *method_handle,
579                                       GnomeVFSSeekPosition  whence,
580                                       GnomeVFSFileOffset    offset
581                                       GnomeVFSCancellation *cancellation);
582
583 GnomeVFSResult (* tell)              (GnomeVFSMethodHandle *method_handle,
584                                       GnomeVFSFileOffset *offset_return);
585
586 GnomeVFSResult (* truncate)          (GnomeVFSMethodHandle *method_handle,
587                                       GnomeVFSFileSize where
588                                       GnomeVFSCancellation *cancellation);
589
590 GnomeVFSResult (* open_directory)    (GnomeVFSMethodHandle **method_handle,
591                                       GnomeVFSURI *uri,
592                                       GnomeVFSFileInfoOptions options,
593                                       const GList *meta_keys,
594                                       const GnomeVFSDirectoryFilter *filter
595                                       GnomeVFSCancellation *cancellation);
596
597 GnomeVFSResult (* close_directory)   (GnomeVFSMethodHandle *method_handle
598                                       GnomeVFSCancellation *cancellation);
599
600 GnomeVFSResult (* read_directory)    (GnomeVFSMethodHandle *method_handle,
601                                       GnomeVFSFileInfo *file_info
602                                       GnomeVFSCancellation *cancellation);
603
604 GnomeVFSResult (* get_file_info)     (GnomeVFSURI *uri,
605                                       GnomeVFSFileInfo *file_info,
606                                       GnomeVFSFileInfoOptions options,
607                                       const GList *meta_keys
608                                       GnomeVFSCancellation *cancellation);
609
610 GnomeVFSResult (* get_file_info_from_handle)
611                                      (GnomeVFSMethodHandle *method_handle,
612                                       GnomeVFSFileInfo *file_info,
613                                       GnomeVFSFileInfoOptions options,
614                                       const GList *meta_keys
615                                       GnomeVFSCancellation *cancellation);
616
617 gboolean       (* is_local)          (const GnomeVFSURI *uri
618                                       GnomeVFSCancellation *cancellation);
619
620 GnomeVFSResult (* rename)            (GnomeVFSURI *uri, const gchar *new_name
621                                       GnomeVFSCancellation *cancellation);
622
623 GnomeVFSResult (* make_directory)    (GnomeVFSURI *uri, guint perm
624                                       GnomeVFSCancellation *cancellation);
625
626 GnomeVFSResult (* remove_directory)  (GnomeVFSURI *uri
627                                       GnomeVFSCancellation *cancellation);
628
629 GnomeVFSResult (* unlink)            (GnomeVFSURI *uri
630                                       GnomeVFSCancellation *cancellation);</PRE
631 ></DIV
632 ></DIV
633 ><DIV
634 CLASS="REFSECT1"
635 ><A
636 NAME="AEN7712"
637 ></A
638 ><H2
639 >Handling cancellation</H2
640 ><P
641 >As VFS operations might be very long, especially in the case
642     of transient errors (such as a network server that has gone down),
643     the GNOME Virtual File System Library provides a standard way for
644     handling cancellation of VFS operations.</P
645 ><DIV
646 CLASS="REFSECT2"
647 ><A
648 NAME="AEN7715"
649 ></A
650 ><H3
651 >The <SPAN
652 CLASS="STRUCTNAME"
653 >GnomeVFSCancellation</SPAN
654 > object</H3
655 ><P
656 >The object that encapsulates this functionality is
657       <SPAN
658 CLASS="STRUCTNAME"
659 >GnomeVFSCancellation</SPAN
660 >.  Most
661       implementation functions get a pointer to such an object, and are
662       expected to use this object to recognize when an operation should
663       be interrupted.</P
664 ><P
665 >The most simple way to check for a cancellation request is
666       to poll the object with
667       <TT
668 CLASS="FUNCTION"
669 >gnome_vfs_cancellation_check()</TT
670 >:</P
671 ><PRE
672 CLASS="PROGRAMLISTING"
673 >  
674 gboolean gnome_vfs_cancellation_check (GnomeVFSCancellation *cancellation);</PRE
675 ><P
676 >This function will return a nonzero value if the current
677       operation should be cancelled.</P
678 ><P
679 >Notice that cancellation is an asynchronous operation that
680       might happen outside your function, in parallel with the code that
681       you are writing.  For example, in the case of threads, the request
682       will be set in the master thread; in the case of slave
683       CORBA-driven processes, the request will be activated by a Unix
684       signal.  So you can expect a cancellation request to happen (and
685       consequently be signalled in
686       <SPAN
687 CLASS="STRUCTNAME"
688 >GnomeVFSCancellation</SPAN
689 >) at any time.</P
690 ><P
691 >For this reason, you should be calling this function
692       periodically, whenever you are going to perform several
693       iterations of the same task, or execute a single expensive task.
694       When the function returns a nonzero value, the correct way to
695       react is:</P
696 ><P
697 ></P
698 ><OL
699 TYPE="1"
700 ><LI
701 ><P
702 >Clean things up so that the result of the
703         operations that have been performed are all
704         cancelled.</P
705 ></LI
706 ><LI
707 ><P
708 >&#62;Return the
709         <SPAN
710 CLASS="SYMBOL"
711 >GNOME_VFS_ERROR_CANCELLED</SPAN
712 > error
713         code.</P
714 ></LI
715 ></OL
716 ><P
717 >But there are some other situations in which you want to
718       be able to interrupt a I/O operation when a cancellation request
719       is performed.  In such cases, polling is not a viable option.</P
720 ><P
721 >For this reason,
722       <SPAN
723 CLASS="STRUCTNAME"
724 >GnomeVFSCancellation</SPAN
725 > provides an
726       alternative way of sending notifications, using a file
727       descriptor.  To use this feature, you should use the following
728       function:</P
729 ><PRE
730 CLASS="PROGRAMLISTING"
731 >&#13;gint gnome_vfs_cancellation_get_fd (GnomeVFSCancellation *cancellation); </PRE
732 ><P
733 >When this function is called, it will return an open file
734       descriptor, which is the read-side of a pipe.  The pipe will be
735       given a character from the write side as soon as a cancellation
736       request is sent.  For this reason, you can check for a
737       cancellation by using the <TT
738 CLASS="FUNCTION"
739 >select()</TT
740 > system
741       call: as soon as <TT
742 CLASS="FUNCTION"
743 >select</TT
744 > reports that some
745       data is available on the file descriptor, you know that a
746       cancellation is being requested.</P
747 ><P
748 >For example, if you are reading from a file descriptor and
749       you want to check for a pending cancellation at the same time,
750       you can set up <TT
751 CLASS="FUNCTION"
752 >select</TT
753 >for checking if data
754       is available on both the cancellation file descriptor and the
755       file descriptor you are reading from.</P
756 ></DIV
757 ><HR><DIV
758 CLASS="REFSECT2"
759 ><A
760 NAME="AEN7742"
761 ></A
762 ><H3
763 >Dealing with <SPAN
764 CLASS="SYMBOL"
765 >EINTR</SPAN
766 ></H3
767 ><P
768 >In order to maximize the chance of cancelling an operation
769       immediately, the GNOME Virtual File System can sends a signal to
770       the asynchronous thread or process.  This does not happen on all
771       the systems and setups, though.</P
772 ><P
773 >The result of this is that, if a process is in the middle
774       of a Unix system call while receiving this signal, the system
775       call might be interrupted and return a <SPAN
776 CLASS="SYMBOL"
777 >EINTR</SPAN
778 >
779       error.</P
780 ><P
781 >For this reason, when you receive <SPAN
782 CLASS="SYMBOL"
783 >EINTR</SPAN
784 >
785       you should check if a cancellation request is pending, using
786       <TT
787 CLASS="FUNCTION"
788 >gnome_vfs_cancellation_check()</TT
789 > on the
790       <SPAN
791 CLASS="STRUCTNAME"
792 >GnomeVFSCancellation</SPAN
793 > object that the
794       implementation function received:</P
795 ><P
796 ></P
797 ><UL
798 ><LI
799 ><P
800 >If a cancellation is indeed pending
801         (<TT
802 CLASS="FUNCTION"
803 >gnome_vfs_cancellation_check()</TT
804 > returns a
805         nonzero value), you should cancel the operation, cleaning up
806         all the effects, and return
807         <SPAN
808 CLASS="SYMBOL"
809 >GNOME_VFS_ERROR_INTERRUPTED</SPAN
810 > or
811         <SPAN
812 CLASS="SYMBOL"
813 >GNOME_VFS_ERROR_CANCELLED</SPAN
814 ></P
815 ></LI
816 ><LI
817 ><P
818 >Otherwise, retry the system call as you would
819         normally do.</P
820 ></LI
821 ></UL
822 ></DIV
823 ></DIV
824 ><DIV
825 CLASS="REFSECT1"
826 ><A
827 NAME="AEN7760"
828 ></A
829 ><H2
830 >Basic guidelines for writing a module</H2
831 ><P
832 >Writing GNOME VFS modules is easy, but there are a few
833     things that you must keep in mind when hacking them:</P
834 ><P
835 ></P
836 ><UL
837 ><LI
838 ><P
839 >All of the code must be completely thread safe.
840       The reason for this is that the asynchronous GNOME VFS engine
841       will use threads when available; if you don't make sure that the
842       code is thread-safe, every kind of weird and unexpected errors
843       will happen.  As debugging these problems can be very hard, it's
844       important to write the code with threads in mind right from the
845       start.</P
846 ></LI
847 ><LI
848 ><P
849 >Use the special
850       <TT
851 CLASS="FUNCTION"
852 >gnome_vfs_*_cancellable()</TT
853 > VFS functions
854       instead of the standard non-cancellable ones, passing them the
855       same <SPAN
856 CLASS="STRUCTNAME"
857 >GnomeVFSCancellation</SPAN
858 > object you
859       are given, so that the operation can always be interrrupted at
860       any time.</P
861 ></LI
862 ><LI
863 ><P
864 >The code should respect the basic GNOME
865       guidelines for source code indentation and
866       style.</P
867 ></LI
868 ></UL
869 ><DIV
870 CLASS="REFSECT2"
871 ><A
872 NAME="AEN7772"
873 ></A
874 ><H3
875 >How to make the code thread safe</H3
876 ><P
877 >Although it might sound scary at first, making the code
878       for the modules thread safe is not complicated at all.</P
879 ><P
880 >First of all, make sure the amount of global variables is
881       kept to the bare minimum.  If possible, you should avoid them at
882       all cost.</P
883 ><P
884 >For those cases where globals are inevitable (such as
885       caches, connection pools or things like that), you have to make
886       sure every variable is properly associated with a mutex, and
887       that the mutex is locked before every access to this variable
888       and released afterwards.  You can also use
889       <TT
890 CLASS="FUNCTION"
891 >G_LOCK_DEFINE_STATIC</TT
892 >,
893       <TT
894 CLASS="FUNCTION"
895 >G_LOCK</TT
896 > and <TT
897 CLASS="FUNCTION"
898 >G_UNLOCK</TT
899 >
900       for this.
901       </P
902 ><P
903 >Generally speaking, if you are going to dynamically
904       allocate structures that are shared by more than one
905       operation/file, you should provide all of them with their nice
906       mutex locks.</P
907 ><P
908 >Finally, make sure mutexes are used only if they are
909       available.  One way to do so is to use macros like the
910       following:</P
911 ><PRE
912 CLASS="PROGRAMLISTING"
913 >&#13;#ifdef G_THREADS_ENABLED
914 #define MUTEX_NEW()     g_mutex_new ()
915 #define MUTEX_FREE(a)   g_mutex_free (a)
916 #define MUTEX_LOCK(a)   if ((a) != NULL) g_mutex_lock (a)
917 #define MUTEX_UNLOCK(a) if ((a) != NULL) g_mutex_unlock (a)
918 #else
919 #define MUTEX_NEW()     NULL
920 #define MUTEX_FREE(a)
921 #define MUTEX_LOCK(a)
922 #define MUTEX_UNLOCK(a)
923 #endif</PRE
924 ><P
925 ><TT
926 CLASS="FUNCTION"
927 >G_LOCK_DEFINE_STATIC</TT
928 >,
929       <TT
930 CLASS="FUNCTION"
931 >G_LOCK</TT
932 > and <TT
933 CLASS="FUNCTION"
934 >G_UNLOCK</TT
935 > in
936       GLib are always safe to use, as they are already defined to be
937       nothing when thread support is not available.</P
938 ><P
939 >(Probably it would be a good idea to have something in the
940       private GNOME VFS API that does this stuff for all the
941       modules.)</P
942 ></DIV
943 ></DIV
944 ><TABLE
945 CLASS="navigation"
946 WIDTH="100%"
947 SUMMARY="Navigation footer"
948 CELLPADDING="2"
949 CELLSPACING="2"
950 ><TR
951 VALIGN="middle"
952 ><TD
953 ALIGN="left"
954 ><A
955 ACCESSKEY="p"
956 HREF="modules.html"
957 ><B
958 >&lt;&lt;&lt;&nbsp;Filesystem Modules</B
959 ></A
960 ></TD
961 ><TD
962 ALIGN="right"
963 ><A
964 ACCESSKEY="n"
965 HREF="gnome-vfs-gnome-vfs-mime.html"
966 ><B
967 >MIME typing&nbsp;&gt;&gt;&gt;</B
968 ></A
969 ></TD
970 ></TR
971 ></TABLE
972 ></BODY
973 ></HTML
974 >