source: mainline/uspace/lib/posix/stdlib.c@ 96646a6

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 96646a6 was 0d33863, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 14 years ago

getloadavg() implementation.

  • Property mode set to 100644
File size: 12.0 KB
Line 
1/*
2 * Copyright (c) 2011 Petr Koupy
3 * Copyright (c) 2011 Jiri Zarevucky
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/** @addtogroup libposix
31 * @{
32 */
33/** @file Standard library definitions.
34 */
35
36#define LIBPOSIX_INTERNAL
37
38#include "internal/common.h"
39#include "stdlib.h"
40
41#include "errno.h"
42#include "fcntl.h"
43#include "limits.h"
44#include "string.h"
45#include "sys/stat.h"
46#include "unistd.h"
47
48#include "libc/sort.h"
49#include "libc/str.h"
50#include "libc/vfs/vfs.h"
51#include "libc/stats.h"
52
53/**
54 *
55 * @param array
56 * @param count
57 * @param size
58 * @param compare
59 */
60int posix_atexit(void (*func)(void))
61{
62 // TODO: low priority, just a compile-time dependency of binutils
63 not_implemented();
64}
65
66/**
67 * Integer absolute value.
68 *
69 * @param i Input value.
70 * @return Absolute value of the parameter.
71 */
72int posix_abs(int i)
73{
74 return i < 0 ? -i : i;
75}
76
77/**
78 * Long integer absolute value.
79 *
80 * @param i Input value.
81 * @return Absolute value of the parameter.
82 */
83long posix_labs(long i)
84{
85 return i < 0 ? -i : i;
86}
87
88/**
89 * Long long integer absolute value.
90 *
91 * @param i Input value.
92 * @return Absolute value of the parameter.
93 */
94long long posix_llabs(long long i)
95{
96 return i < 0 ? -i : i;
97}
98
99/**
100 * Compute the quotient and remainder of an integer division.
101 *
102 * @param numer Numerator.
103 * @param denom Denominator.
104 * @return Quotient and remainder packed into structure.
105 */
106posix_div_t posix_div(int numer, int denom)
107{
108 return (posix_div_t) { .quot = numer / denom, .rem = numer % denom };
109}
110
111/**
112 * Compute the quotient and remainder of a long integer division.
113 *
114 * @param numer Numerator.
115 * @param denom Denominator.
116 * @return Quotient and remainder packed into structure.
117 */
118posix_ldiv_t posix_ldiv(long numer, long denom)
119{
120 return (posix_ldiv_t) { .quot = numer / denom, .rem = numer % denom };
121}
122
123/**
124 * Compute the quotient and remainder of a long long integer division.
125 *
126 * @param numer Numerator.
127 * @param denom Denominator.
128 * @return Quotient and remainder packed into structure.
129 */
130posix_lldiv_t posix_lldiv(long long numer, long long denom)
131{
132 return (posix_lldiv_t) { .quot = numer / denom, .rem = numer % denom };
133}
134
135/**
136 * Private helper function that serves as a compare function for qsort().
137 *
138 * @param elem1 First element to compare.
139 * @param elem2 Second element to compare.
140 * @param compare Comparison function without userdata parameter.
141 * @return Relative ordering of the elements.
142 */
143static int sort_compare_wrapper(void *elem1, void *elem2, void *userdata)
144{
145 int (*compare)(const void *, const void *) = userdata;
146 int ret = compare(elem1, elem2);
147
148 /* Native qsort internals expect this. */
149 if (ret < 0) {
150 return -1;
151 } else if (ret > 0) {
152 return 1;
153 } else {
154 return 0;
155 }
156}
157
158/**
159 * Array sorting utilizing the quicksort algorithm.
160 *
161 * @param array Array of elements to sort.
162 * @param count Number of elements in the array.
163 * @param size Width of each element.
164 * @param compare Decides relative ordering of two elements.
165 */
166void posix_qsort(void *array, size_t count, size_t size,
167 int (*compare)(const void *, const void *))
168{
169 /* Implemented in libc with one extra argument. */
170 qsort(array, count, size, sort_compare_wrapper, compare);
171}
172
173/**
174 * Binary search in a sorted array.
175 *
176 * @param key Object to search for.
177 * @param base Pointer to the first element of the array.
178 * @param nmemb Number of elements in the array.
179 * @param size Size of each array element.
180 * @param compar Comparison function.
181 * @return Pointer to a matching element, or NULL if none can be found.
182 */
183void *posix_bsearch(const void *key, const void *base,
184 size_t nmemb, size_t size, int (*compar)(const void *, const void *))
185{
186 while (nmemb > 0) {
187 const void *middle = base + (nmemb / 2) * size;
188 int cmp = compar(key, middle);
189 if (cmp == 0) {
190 return (void *) middle;
191 }
192 if (middle == base) {
193 /* There is just one member left to check and it
194 * didn't match the key. Avoid infinite loop.
195 */
196 break;
197 }
198 if (cmp < 0) {
199 nmemb = nmemb / 2;
200 } else if (cmp > 0) {
201 nmemb = nmemb - (nmemb / 2);
202 base = middle;
203 }
204 }
205
206 return NULL;
207}
208
209/**
210 * Retrieve a value of the given environment variable.
211 *
212 * Since HelenOS doesn't support env variables at the moment,
213 * this function always returns NULL.
214 *
215 * @param name Name of the variable.
216 * @return Value of the variable or NULL if such variable does not exist.
217 */
218char *posix_getenv(const char *name)
219{
220 return NULL;
221}
222
223/**
224 *
225 * @param name
226 * @param resolved
227 * @return
228 */
229int posix_putenv(char *string)
230{
231 // TODO: low priority, just a compile-time dependency of binutils
232 not_implemented();
233}
234
235/**
236 * Issue a command.
237 *
238 * @param string String to be passed to a command interpreter or NULL.
239 * @return Termination status of the command if the command is not NULL,
240 * otherwise indicate whether there is a command interpreter (non-zero)
241 * or not (zero).
242 */
243int posix_system(const char *string) {
244 // TODO: does nothing at the moment
245 return 0;
246}
247
248/**
249 * Resolve absolute pathname.
250 *
251 * @param name Pathname to be resolved.
252 * @param resolved Either buffer for the resolved absolute pathname or NULL.
253 * @return On success, either resolved (if it was not NULL) or pointer to the
254 * newly allocated buffer containing the absolute pathname (if resolved was
255 * NULL). Otherwise NULL.
256 *
257 */
258char *posix_realpath(const char *restrict name, char *restrict resolved)
259{
260 #ifndef PATH_MAX
261 assert(resolved == NULL);
262 #endif
263
264 if (name == NULL) {
265 errno = EINVAL;
266 return NULL;
267 }
268
269 // TODO: symlink resolution
270
271 /* Function absolutize is implemented in libc and declared in vfs.h.
272 * No more processing is required as HelenOS doesn't have symlinks
273 * so far (as far as I can tell), although this function will need
274 * to be updated when that support is implemented.
275 */
276 char* absolute = absolutize(name, NULL);
277
278 if (absolute == NULL) {
279 /* POSIX requires some specific errnos to be set
280 * for some cases, but there is no way to find out from
281 * absolutize().
282 */
283 errno = EINVAL;
284 return NULL;
285 }
286
287 if (resolved == NULL) {
288 return absolute;
289 } else {
290 #ifdef PATH_MAX
291 str_cpy(resolved, PATH_MAX, absolute);
292 #endif
293 free(absolute);
294 return resolved;
295 }
296}
297
298/**
299 * Converts a string representation of a floating-point number to
300 * its native representation. See posix_strtold().
301 *
302 * @param nptr String representation of a floating-point number.
303 * @return Double-precision number resulting from the string conversion.
304 */
305double posix_atof(const char *nptr)
306{
307 return posix_strtod(nptr, NULL);
308}
309
310/**
311 * Converts a string representation of a floating-point number to
312 * its native representation. See posix_strtold().
313 *
314 * @param nptr String representation of a floating-point number.
315 * @param endptr Pointer to the final part of the string which
316 * was not used for conversion.
317 * @return Single-precision number resulting from the string conversion.
318 */
319float posix_strtof(const char *restrict nptr, char **restrict endptr)
320{
321 return (float) posix_strtold(nptr, endptr);
322}
323
324/**
325 * Converts a string representation of a floating-point number to
326 * its native representation. See posix_strtold().
327 *
328 * @param nptr String representation of a floating-point number.
329 * @param endptr Pointer to the final part of the string which
330 * was not used for conversion.
331 * @return Double-precision number resulting from the string conversion.
332 */
333double posix_strtod(const char *restrict nptr, char **restrict endptr)
334{
335 return (double) posix_strtold(nptr, endptr);
336}
337
338/**
339 * Allocate memory chunk.
340 *
341 * @param size Size of the chunk to allocate.
342 * @return Either pointer to the allocated chunk or NULL if not possible.
343 */
344void *posix_malloc(size_t size)
345{
346 return malloc(size);
347}
348
349/**
350 * Allocate memory for an array of elements.
351 *
352 * @param nelem Number of elements in the array.
353 * @param elsize Size of each element.
354 * @return Either pointer to the allocated array or NULL if not possible.
355 */
356void *posix_calloc(size_t nelem, size_t elsize)
357{
358 return calloc(nelem, elsize);
359}
360
361/**
362 * Reallocate memory chunk to a new size.
363 *
364 * @param ptr Memory chunk to reallocate. Might be NULL.
365 * @param size Size of the reallocated chunk. Might be zero.
366 * @return Either NULL or the pointer to the newly reallocated chunk.
367 */
368void *posix_realloc(void *ptr, size_t size)
369{
370 if (ptr != NULL && size == 0) {
371 /* Native realloc does not handle this special case. */
372 free(ptr);
373 return NULL;
374 } else {
375 return realloc(ptr, size);
376 }
377}
378
379/**
380 * Free allocated memory chunk.
381 *
382 * @param ptr Memory chunk to be freed.
383 */
384void posix_free(void *ptr)
385{
386 if (ptr) {
387 free(ptr);
388 }
389}
390
391/**
392 * Creates and opens an unique temporary file from template.
393 *
394 * @param tmpl Template. Last six characters must be XXXXXX.
395 * @return The opened file descriptor or -1 on error.
396 */
397int posix_mkstemp(char *tmpl)
398{
399 int fd = -1;
400
401 char *tptr = tmpl + posix_strlen(tmpl) - 6;
402
403 while (fd < 0) {
404 if (*posix_mktemp(tmpl) == '\0') {
405 /* Errno set by mktemp(). */
406 return -1;
407 }
408
409 fd = open(tmpl, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
410
411 if (fd == -1) {
412 /* Restore template to it's original state. */
413 snprintf(tptr, 7, "XXXXXX");
414 }
415 }
416
417 return fd;
418}
419
420/**
421 * Creates an unique temporary file name from template.
422 *
423 * @param tmpl Template. Last six characters must be XXXXXX.
424 * @return The value of tmpl. The template is modified in place.
425 * If no temporary file name can be created, template is
426 * reduced to an empty string.
427 */
428char *posix_mktemp(char *tmpl)
429{
430 int tmpl_len = posix_strlen(tmpl);
431 if (tmpl_len < 6) {
432 errno = EINVAL;
433 *tmpl = '\0';
434 return tmpl;
435 }
436
437 char *tptr = tmpl + tmpl_len - 6;
438 if (posix_strcmp(tptr, "XXXXXX") != 0) {
439 errno = EINVAL;
440 *tmpl = '\0';
441 return tmpl;
442 }
443
444 static int seq = 0;
445
446 for (; seq < 1000000; ++seq) {
447 snprintf(tptr, 7, "%06d", seq);
448
449 int orig_errno = errno;
450 errno = 0;
451 /* Check if the file exists. */
452 if (posix_access(tmpl, F_OK) == -1) {
453 if (errno == ENOENT) {
454 errno = orig_errno;
455 break;
456 } else {
457 /* errno set by access() */
458 *tmpl = '\0';
459 return tmpl;
460 }
461 }
462 }
463
464 if (seq == 10000000) {
465 errno = EEXIST;
466 *tmpl = '\0';
467 return tmpl;
468 }
469
470 return tmpl;
471}
472
473/**
474 * Get system load average statistics.
475 *
476 * @param loadavg Array where the load averages shall be placed.
477 * @param nelem Maximum number of elements to be placed into the array.
478 * @return Number of elements placed into the array on success, -1 otherwise.
479 */
480int bsd_getloadavg(double loadavg[], int nelem)
481{
482 assert(nelem > 0);
483
484 size_t count;
485 load_t *loads = stats_get_load(&count);
486
487 if (loads == NULL) {
488 return -1;
489 }
490
491 if (((size_t) nelem) < count) {
492 count = nelem;
493 }
494
495 for (size_t i = 0; i < count; ++i) {
496 loadavg[i] = (double) loads[i];
497 }
498
499 free(loads);
500 return count;
501}
502
503/** @}
504 */
Note: See TracBrowser for help on using the repository browser.