XBPS Library API 20240111
The X Binary Package System
plist.c
1/*-
2 * Copyright (c) 2008-2015 Juan Romero Pardines.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include <errno.h>
27#include <pthread.h>
28#include <stdbool.h>
29#include <stdio.h>
30#include <stdlib.h>
31#include <string.h>
32#include <unistd.h>
33
34#include "xbps_api_impl.h"
35
36struct thread_data {
37 pthread_t thread;
38 xbps_array_t array;
39 xbps_dictionary_t dict;
40 struct xbps_handle *xhp;
41 unsigned int start;
42 unsigned int arraycount;
43 unsigned int *reserved;
44 pthread_mutex_t *reserved_lock;
45 unsigned int slicecount;
46 int (*fn)(struct xbps_handle *, xbps_object_t, const char *, void *, bool *);
47 void *fn_arg;
48};
49
50/**
51 * @file lib/plist.c
52 * @brief PropertyList generic routines
53 * @defgroup plist PropertyList generic functions
54 *
55 * These functions manipulate plist files and objects shared by almost
56 * all library functions.
57 */
58static void *
59array_foreach_thread(void *arg)
60{
61 xbps_object_t obj, pkgd;
62 struct thread_data *thd = arg;
63 const char *key;
64 int rv;
65 bool loop_done = false;
66 unsigned i = thd->start;
67 unsigned int end = i + thd->slicecount;
68
69 while(i < thd->arraycount) {
70 /* process pkgs from start until end */
71 for (; i < end && i < thd->arraycount; i++) {
72 obj = xbps_array_get(thd->array, i);
73 if (xbps_object_type(thd->dict) == XBPS_TYPE_DICTIONARY) {
74 pkgd = xbps_dictionary_get_keysym(thd->dict, obj);
75 key = xbps_dictionary_keysym_cstring_nocopy(obj);
76 /* ignore internal objs */
77 if (strncmp(key, "_XBPS_", 6) == 0)
78 continue;
79 } else {
80 pkgd = obj;
81 key = NULL;
82 }
83 rv = (*thd->fn)(thd->xhp, pkgd, key, thd->fn_arg, &loop_done);
84 if (rv != 0 || loop_done)
85 return NULL;
86 }
87 /* Reserve more elements to compute */
88 pthread_mutex_lock(thd->reserved_lock);
89 i = *thd->reserved;
90 end = i + thd->slicecount;
91 *thd->reserved = end;
92 pthread_mutex_unlock(thd->reserved_lock);
93 }
94 return NULL;
95}
96
97int
99 xbps_array_t array,
100 xbps_dictionary_t dict,
101 int (*fn)(struct xbps_handle *, xbps_object_t, const char *, void *, bool *),
102 void *arg)
103{
104 struct thread_data *thd;
105 unsigned int arraycount, slicecount;
106 int rv = 0, error = 0, i, maxthreads;
107 unsigned int reserved;
108 pthread_mutex_t reserved_lock = PTHREAD_MUTEX_INITIALIZER;
109
110 assert(fn != NULL);
111
112 if (xbps_object_type(array) != XBPS_TYPE_ARRAY)
113 return 0;
114
115 arraycount = xbps_array_count(array);
116 if (arraycount == 0)
117 return 0;
118
119 maxthreads = (int)sysconf(_SC_NPROCESSORS_ONLN);
120 if (maxthreads <= 1 || arraycount <= 1) /* use single threaded routine */
121 return xbps_array_foreach_cb(xhp, array, dict, fn, arg);
122
123 thd = calloc(maxthreads, sizeof(*thd));
124 assert(thd);
125
126 // maxthread is boundchecked to be > 1
127 if((unsigned int)maxthreads >= arraycount) {
128 maxthreads = arraycount;
129 slicecount = 1;
130 } else {
131 slicecount = arraycount / maxthreads;
132 if (slicecount > 32) {
133 slicecount = 32;
134 }
135 }
136
137 reserved = slicecount * maxthreads;
138
139 for (i = 0; i < maxthreads; i++) {
140 thd[i].array = array;
141 thd[i].dict = dict;
142 thd[i].xhp = xhp;
143 thd[i].fn = fn;
144 thd[i].fn_arg = arg;
145 thd[i].start = i * slicecount;
146 thd[i].reserved = &reserved;
147 thd[i].reserved_lock = &reserved_lock;
148 thd[i].slicecount = slicecount;
149 thd[i].arraycount = arraycount;
150
151 if ((rv = pthread_create(&thd[i].thread, NULL, array_foreach_thread, &thd[i])) != 0) {
152 error = rv;
153 break;
154 }
155
156 }
157 /* wait for all threads that were created successfully */
158 for (int c = 0; c < i; c++) {
159 if ((rv = pthread_join(thd[c].thread, NULL)) != 0)
160 error = rv;
161 }
162
163 free(thd);
164 pthread_mutex_destroy(&reserved_lock);
165
166 return error ? error : rv;
167}
168
169int
171 xbps_array_t array,
172 xbps_dictionary_t dict,
173 int (*fn)(struct xbps_handle *, xbps_object_t, const char *, void *, bool *),
174 void *arg)
175{
176 xbps_dictionary_t pkgd;
177 xbps_object_t obj;
178 const char *key;
179 int rv = 0;
180 bool loop_done = false;
181
182 for (unsigned int i = 0; i < xbps_array_count(array); i++) {
183 obj = xbps_array_get(array, i);
184 if (xbps_object_type(dict) == XBPS_TYPE_DICTIONARY) {
185 pkgd = xbps_dictionary_get_keysym(dict, obj);
186 key = xbps_dictionary_keysym_cstring_nocopy(obj);
187 /* ignore internal objs */
188 if (strncmp(key, "_XBPS_", 6) == 0)
189 continue;
190 } else {
191 pkgd = obj;
192 key = NULL;
193 }
194 rv = (*fn)(xhp, pkgd, key, arg, &loop_done);
195 if (rv != 0 || loop_done)
196 break;
197 }
198 return rv;
199}
200
201xbps_object_iterator_t
202xbps_array_iter_from_dict(xbps_dictionary_t dict, const char *key)
203{
204 xbps_array_t array;
205
206 assert(xbps_object_type(dict) == XBPS_TYPE_DICTIONARY);
207 assert(key != NULL);
208
209 array = xbps_dictionary_get(dict, key);
210 if (xbps_object_type(array) != XBPS_TYPE_ARRAY) {
211 errno = EINVAL;
212 return NULL;
213 }
214
215 return xbps_array_iterator(array);
216}
217
218static int
219array_replace_dict(xbps_array_t array,
220 xbps_dictionary_t dict,
221 const char *str,
222 bool bypattern)
223{
224 xbps_object_t obj;
225 const char *pkgver, *pkgname;
226
227 assert(xbps_object_type(array) == XBPS_TYPE_ARRAY);
228 assert(xbps_object_type(dict) == XBPS_TYPE_DICTIONARY);
229 assert(str != NULL);
230
231 for (unsigned int i = 0; i < xbps_array_count(array); i++) {
232 obj = xbps_array_get(array, i);
233 if (obj == NULL) {
234 continue;
235 }
236 if (!xbps_dictionary_get_cstring_nocopy(obj, "pkgver", &pkgver)) {
237 continue;
238 }
239 if (bypattern) {
240 /* pkgpattern match */
241 if (xbps_pkgpattern_match(pkgver, str)) {
242 if (!xbps_array_set(array, i, dict)) {
243 return EINVAL;
244 }
245 return 0;
246 }
247 } else {
248 /* pkgname match */
249 xbps_dictionary_get_cstring_nocopy(obj, "pkgname", &pkgname);
250 if (strcmp(pkgname, str) == 0) {
251 if (!xbps_array_set(array, i, dict)) {
252 return EINVAL;
253 }
254 return 0;
255 }
256 }
257 }
258 /* no match */
259 return ENOENT;
260}
261
262int HIDDEN
263xbps_array_replace_dict_by_name(xbps_array_t array,
264 xbps_dictionary_t dict,
265 const char *pkgver)
266{
267 return array_replace_dict(array, dict, pkgver, false);
268}
269
270int HIDDEN
271xbps_array_replace_dict_by_pattern(xbps_array_t array,
272 xbps_dictionary_t dict,
273 const char *pattern)
274{
275 return array_replace_dict(array, dict, pattern, true);
276}
Generic XBPS structure handler for initialization.
Definition xbps.h:550
xbps_object_iterator_t xbps_array_iter_from_dict(xbps_dictionary_t dict, const char *key)
Definition plist.c:202
int xbps_array_foreach_cb_multi(struct xbps_handle *xhp, xbps_array_t array, xbps_dictionary_t dict, int(*fn)(struct xbps_handle *, xbps_object_t obj, const char *, void *arg, bool *done), void *arg)
int xbps_array_foreach_cb(struct xbps_handle *xhp, xbps_array_t array, xbps_dictionary_t dict, int(*fn)(struct xbps_handle *, xbps_object_t obj, const char *, void *arg, bool *done), void *arg)
int xbps_pkgpattern_match(const char *pkgver, const char *pattern)
Definition util.c:530