Buffer Management

How to allocate buffer memory

Some objects, such as the sock or ser, rely on buffers for storing the data being sent and received. For example, each serial port of the ser object has two buffers- RX and TX, while each socket of the sock object has 6 different buffers.

By default, all buffers have no memory allocated for them, which basically means that they cannot store any data. For related objects to work, these buffers need to be given memory.

Memory is allocated in pages. Each page equals 256 bytes. There is a small overhead for each buffer- 16 bytes are used for internal buffer houskeeping (variables, pointers, etc.). Therefore, if you have allocated 2 pages for a particular buffer, then this buffer's actual capacity will be 2*256-16= 496 bytes.

Buffer memory allocation is a two-step process. First, you request certain number of pages for each port, socket, etc. that you plan to use. This is done through methods of corresponding objects. For example, the ser.rxbuffrq method requests buffer memory for the RX buffer of one of the serial ports. Similar methods exist for all other buffers of all objects that require buffer memory. Note, that actual memory allocation does not happen at this stage- only your "requests" are collected.

After all requests have been made actual memory allocation is performed by using the sys.buffalloc method. This allocates memory, as per previous requests, for all buffers of all objects. Here is an example:

** Tibbo Basic **

'allocate memory for RX and TX buffers of serial port 0 and socket 0

'make requests
ser.num= 0
ser.rxbuffrq= 5
ser.txbuffrq= 5
sock.rxbuffrq= 4
sock.txbuffrq= 4

'and now actual allocation

Typically, buffer memory allocation is done in the on_sys_init event handler but you don't have to do it this way. In fact, your application can re-allocate buffer memory space according to the changes in the operating mode or other conditions.

Sys.buffalloc could take up to several hundred milliseconds to execute, so it makes sense to use it as little as possible. Hence, request all necessary buffer allocations first, then use the sys.buffalloc once to finish the job.

Buffer (re)allocation for a specific object will only work if the corresponding object or part of the object to which this buffer belongs is idle. "Part" refers to a particular serial port of the ser object, or particular socket of the sock object, etc. to which the buffer you are trying to change belongs. "Idle" means different things for different objects: ser.enabled= 0- NO for the serial port, sock.statesimple=  0- PL_SSTS_CLOSED for the socket, etc.

Intelligent memory allocation basing on what's available

Memory is not an infinite resource and you will not always get as much memory as you have requested. Methods such as the ser.rxbuffrq actually return the amount of memory that can be allocated:

** Tibbo Basic **

dim x as byte
x=ser.rxbuffrq(5) 'x could get less than 5, which means that you got less memory than you have asked for

Two properties of the sock object were implemented to help you allocate memory intelligently, basing on what is available.

The sys.totalbuffpages read-only property tells you how many buffer pages are there on your system in total. This is defined by the amount of physical variable memory (RAM) available minus memory required to store your project's variables (so, as your project grows available buffer memory shrinks).

The sys.freebuffpages read-only property tells you the amount of free (not yet allocated) buffer pages.

Here is an example in which we allocate memory equally between the TX and RX buffers of four serial ports and four sockets:

** Tibbo Basic **

dim x,f as byte

x=sys.totalbuffpages/16 'will work correctly if we haven't allocated anything yet

for f=0 to 3
 ser.num= f
 sock.num= f
next f

In the above example we do not check what individual buffer requests return because we have already calculated each buffer's size basing on the total number of buffer pages available.