1 /* Copyright (C) 2001-2012 Artifex Software, Inc.
2    All Rights Reserved.
3 
4    This software is provided AS-IS with no warranty, either express or
5    implied.
6 
7    This software is distributed under license and may not be copied,
8    modified or distributed except as expressly authorized under the terms
9    of the license contained in the file LICENSE in this distribution.
10 
11    Refer to licensing information at http://www.artifex.com or contact
12    Artifex Software, Inc.,  7 Mt. Lassen Drive - Suite A-134, San Rafael,
13    CA  94903, U.S.A., +1(415)492-9861, for further information.
14 */
15 
16 
17 /* Notification machinery implementation */
18 #include "gx.h"
19 #include "gserrors.h"
20 #include "gsstruct.h"
21 #include "gsnotify.h"
22 
23 /* GC descriptors */
24 private_st_gs_notify_registration();
25 public_st_gs_notify_list();
26 
27 /* Initialize a notification list. */
28 void
gs_notify_init(gs_notify_list_t * nlist,gs_memory_t * mem)29 gs_notify_init(gs_notify_list_t *nlist, gs_memory_t *mem)
30 {
31     nlist->first = 0;
32     nlist->memory = mem;
33 }
34 
35 /* Register a client. */
36 int
gs_notify_register(gs_notify_list_t * nlist,gs_notify_proc_t proc,void * proc_data)37 gs_notify_register(gs_notify_list_t *nlist, gs_notify_proc_t proc,
38                    void *proc_data)
39 {
40     gs_notify_registration_t *nreg =
41         gs_alloc_struct(nlist->memory, gs_notify_registration_t,
42                         &st_gs_notify_registration, "gs_notify_register");
43 
44     if (nreg == 0)
45         return_error(gs_error_VMerror);
46     nreg->proc = proc;
47     nreg->proc_data = proc_data;
48     nreg->next = nlist->first;
49     nlist->first = nreg;
50     return 0;
51 }
52 
53 /*
54  * Unregister a client.  Return 1 if the client was registered, 0 if not.
55  * If proc_data is 0, unregister all registrations of that proc; otherwise,
56  * unregister only the registration of that procedure with that proc_data.
57  */
58 static void
no_unreg_proc(void * pdata)59 no_unreg_proc(void *pdata)
60 {
61 }
62 int
gs_notify_unregister_calling(gs_notify_list_t * nlist,gs_notify_proc_t proc,void * proc_data,void (* unreg_proc)(void * pdata))63 gs_notify_unregister_calling(gs_notify_list_t *nlist, gs_notify_proc_t proc,
64                              void *proc_data,
65                              void (*unreg_proc)(void *pdata))
66 {
67     gs_notify_registration_t **prev = &nlist->first;
68     gs_notify_registration_t *cur;
69     bool found = 0;
70 
71     while ((cur = *prev) != 0)
72         if (cur->proc == proc &&
73             (proc_data == 0 || cur->proc_data == proc_data)
74             ) {
75             *prev = cur->next;
76             unreg_proc(cur->proc_data);
77             gs_free_object(nlist->memory, cur, "gs_notify_unregister");
78             found = 1;
79         } else
80             prev = &cur->next;
81     return found;
82 }
83 int
gs_notify_unregister(gs_notify_list_t * nlist,gs_notify_proc_t proc,void * proc_data)84 gs_notify_unregister(gs_notify_list_t *nlist, gs_notify_proc_t proc,
85                      void *proc_data)
86 {
87     return gs_notify_unregister_calling(nlist, proc, proc_data, no_unreg_proc);
88 }
89 
90 /*
91  * Notify the clients on a list.  If an error occurs, return the first
92  * error code, but notify all clients regardless.
93  */
94 int
gs_notify_all(gs_notify_list_t * nlist,void * event_data)95 gs_notify_all(gs_notify_list_t *nlist, void *event_data)
96 {
97     gs_notify_registration_t *cur;
98     gs_notify_registration_t *next;
99     int ecode = 0;
100 
101     for (next = nlist->first; (cur = next) != 0;) {
102         int code;
103 
104         next = cur->next;
105         code = cur->proc(cur->proc_data, event_data);
106         if (code < 0 && ecode == 0)
107             ecode = code;
108     }
109     return ecode;
110 }
111 
112 /* Release a notification list. */
113 void
gs_notify_release(gs_notify_list_t * nlist)114 gs_notify_release(gs_notify_list_t *nlist)
115 {
116     gs_memory_t *mem = nlist->memory;
117 
118     while (nlist->first) {
119         gs_notify_registration_t *next = nlist->first->next;
120 
121         gs_free_object(mem, nlist->first, "gs_notify_release");
122         nlist->first = next;
123     }
124 }
125