libsigrok
datastore.c
Go to the documentation of this file.
00001 /*
00002  * This file is part of the sigrok project.
00003  *
00004  * Copyright (C) 2010-2012 Bert Vermeulen <bert@biot.com>
00005  *
00006  * This program is free software: you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation, either version 3 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00018  */
00019 
00020 #include <stdlib.h>
00021 #include <stdint.h>
00022 #include <string.h>
00023 #include <glib.h>
00024 #include "sigrok.h"
00025 #include "sigrok-internal.h"
00026 
00027 static gpointer new_chunk(struct sr_datastore **ds);
00028 
00029 /**
00030  * Create a new datastore with the specified unit size.
00031  *
00032  * The unit size is fixed once the datastore is created, and cannot be
00033  * changed later on, neither can data be added to the datastore with
00034  * different unit sizes later.
00035  *
00036  * It is the caller's responsibility to free the allocated memory of the
00037  * datastore via the sr_datastore_destroy() function, if no longer needed.
00038  *
00039  * TODO: Unitsize should probably be unsigned int or uint32_t or similar.
00040  * TODO: This function should have a 'chunksize' parameter, and
00041  *       struct sr_datastore a 'chunksize' field.
00042  *
00043  * @param unitsize The unit size (>= 1) to be used for this datastore.
00044  * @param ds Pointer to a variable which will hold the newly created
00045  *           datastore structure.
00046  *           
00047  * @return SR_OK upon success, SR_ERR_MALLOC upon memory allocation errors,
00048  *         or SR_ERR_ARG upon invalid arguments. If something other than SR_OK
00049  *         is returned, the value of 'ds' is undefined.
00050  */
00051 SR_API int sr_datastore_new(int unitsize, struct sr_datastore **ds)
00052 {
00053         if (!ds) {
00054                 sr_err("ds: %s: ds was NULL", __func__);
00055                 return SR_ERR_ARG;
00056         }
00057 
00058         if (unitsize <= 0) {
00059                 sr_err("ds: %s: unitsize was %d, but it must be >= 1",
00060                        __func__, unitsize);
00061                 return SR_ERR_ARG;
00062         }
00063 
00064         if (!(*ds = g_try_malloc(sizeof(struct sr_datastore)))) {
00065                 sr_err("ds: %s: ds malloc failed", __func__);
00066                 return SR_ERR_MALLOC;
00067         }
00068 
00069         (*ds)->ds_unitsize = unitsize;
00070         (*ds)->num_units = 0;
00071         (*ds)->chunklist = NULL;
00072 
00073         return SR_OK;
00074 }
00075 
00076 /**
00077  * Destroy the specified datastore and free the memory used by it.
00078  *
00079  * This will free the memory used by the data in the datastore's 'chunklist',
00080  * by the chunklist data structure itself, and by the datastore struct.
00081  *
00082  * @param ds The datastore to destroy.
00083  *
00084  * @return SR_OK upon success, SR_ERR_ARG upon invalid arguments.
00085  */
00086 SR_API int sr_datastore_destroy(struct sr_datastore *ds)
00087 {
00088         GSList *chunk;
00089 
00090         if (!ds) {
00091                 sr_err("ds: %s: ds was NULL", __func__);
00092                 return SR_ERR_ARG;
00093         }
00094 
00095         for (chunk = ds->chunklist; chunk; chunk = chunk->next)
00096                 g_free(chunk->data);
00097         g_slist_free(ds->chunklist);
00098         g_free(ds);
00099         ds = NULL;
00100 
00101         return SR_OK;
00102 }
00103 
00104 /**
00105  * Append some data to the specified datastore.
00106  *
00107  * TODO: More elaborate function description.
00108  *
00109  * TODO: This function should use the (not yet available) 'chunksize' field
00110  *       of struct sr_datastore (instead of hardcoding DATASTORE_CHUNKSIZE).
00111  * TODO: in_unitsize and probelist are unused?
00112  * TODO: A few of the parameters can be const.
00113  * TODO: Ideally, 'ds' should be unmodified upon errors.
00114  *
00115  * @param ds Pointer to the datastore which shall receive the data.
00116  *           Must not be NULL.
00117  * @param data Pointer to the memory buffer containing the data to add.
00118  *             Must not be NULL. TODO: Data format?
00119  * @param length Length of the data to add (in number of bytes).
00120  *               TODO: Should 0 be allowed as length?
00121  * @param in_unitsize The unit size (>= 1) of the input data.
00122  * @param probelist Pointer to a list of integers (probe numbers). The probe
00123  *                  numbers in this list are 1-based, i.e. the first probe
00124  *                  is expected to be numbered 1 (not 0!). Must not be NULL.
00125  *
00126  * @return SR_OK upon success, SR_ERR_MALLOC upon memory allocation errors,
00127  *         or SR_ERR_ARG upon invalid arguments. If something other than SR_OK
00128  *         is returned, the value/state of 'ds' is undefined.
00129  */
00130 SR_API int sr_datastore_put(struct sr_datastore *ds, void *data,
00131                 unsigned int length, int in_unitsize, const int *probelist)
00132 {
00133         unsigned int stored;
00134         int capacity, size, num_chunks, chunk_bytes_free, chunk_offset;
00135         gpointer chunk;
00136 
00137         if (!ds) {
00138                 sr_err("ds: %s: ds was NULL", __func__);
00139                 return SR_ERR_ARG;
00140         }
00141 
00142         /* Unitsize must not be 0, we'll divide by 0 otherwise. */
00143         if (ds->ds_unitsize == 0) {
00144                 sr_err("ds: %s: ds->ds_unitsize was 0", __func__);
00145                 return SR_ERR_ARG;
00146         }
00147 
00148         if (!data) {
00149                 sr_err("ds: %s: data was NULL", __func__);
00150                 return SR_ERR_ARG;
00151         }
00152 
00153         if (in_unitsize < 1) {
00154                 sr_err("ds: %s: in_unitsize was %d, but it must be >= 1",
00155                        __func__, in_unitsize);
00156                 return SR_ERR_ARG;
00157         }
00158 
00159         if (!probelist) {
00160                 sr_err("ds: %s: probelist was NULL", __func__);
00161                 return SR_ERR_ARG;
00162         }
00163 
00164         /* Get the last chunk in the list, or create a new one if needed. */
00165         if (ds->chunklist == NULL) {
00166                 if (!(chunk = new_chunk(&ds))) {
00167                         sr_err("ds: %s: couldn't allocate new chunk", __func__);
00168                         return SR_ERR_MALLOC;
00169                 }
00170         } else {
00171                 chunk = g_slist_last(ds->chunklist)->data;
00172         }
00173 
00174         /* Get/calculate number of chunks, free space, etc. */
00175         num_chunks = g_slist_length(ds->chunklist);
00176         capacity = (num_chunks * DATASTORE_CHUNKSIZE);
00177         chunk_bytes_free = capacity - (ds->ds_unitsize * ds->num_units);
00178         chunk_offset = capacity - (DATASTORE_CHUNKSIZE * (num_chunks - 1))
00179                        - chunk_bytes_free;
00180 
00181         stored = 0;
00182         while (stored < length) {
00183                 /* No more free space left, allocate a new chunk. */
00184                 if (chunk_bytes_free == 0) {
00185                         if (!(chunk = new_chunk(&ds))) {
00186                                 sr_err("ds: %s: couldn't allocate new chunk",
00187                                        __func__);
00188                                 return SR_ERR_MALLOC;
00189                         }
00190                         chunk_bytes_free = DATASTORE_CHUNKSIZE;
00191                         chunk_offset = 0;
00192                 }
00193 
00194                 if (length - stored > (unsigned int)chunk_bytes_free)
00195                         size = chunk_bytes_free;
00196                 else
00197                         /* Last part, won't fill up this chunk. */
00198                         size = length - stored;
00199 
00200                 memcpy(chunk + chunk_offset, data + stored, size);
00201                 chunk_bytes_free -= size;
00202                 stored += size;
00203         }
00204 
00205         ds->num_units += stored / ds->ds_unitsize;
00206 
00207         return SR_OK;
00208 }
00209 
00210 /**
00211  * Allocate a new memory chunk, append it to the datastore's chunklist.
00212  *
00213  * The newly allocated chunk is added to the datastore's chunklist by this
00214  * function, and the return value additionally points to the new chunk.
00215  *
00216  * The allocated memory is guaranteed to be cleared.
00217  *
00218  * TODO: This function should use the datastore's 'chunksize' field instead
00219  *       of hardcoding DATASTORE_CHUNKSIZE.
00220  * TODO: Return int, so we can return SR_OK / SR_ERR_ARG / SR_ERR_MALLOC?
00221  *
00222  * @param ds Pointer to a variable which holds the datastore structure.
00223  *           Must not be NULL. The contents of 'ds' are modified in-place.
00224  *
00225  * @return Pointer to the newly allocated chunk, or NULL upon failure.
00226  */
00227 static gpointer new_chunk(struct sr_datastore **ds)
00228 {
00229         gpointer chunk;
00230 
00231         /* Note: Caller checked that ds != NULL. */
00232 
00233         chunk = g_try_malloc0(DATASTORE_CHUNKSIZE * (*ds)->ds_unitsize);
00234         if (!chunk) {
00235                 sr_err("ds: %s: chunk malloc failed", __func__);
00236                 return NULL; /* TODO: SR_ERR_MALLOC later? */
00237         }
00238 
00239         (*ds)->chunklist = g_slist_append((*ds)->chunklist, chunk);
00240 
00241         return chunk; /* TODO: SR_OK later? */
00242 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines